package tech.easyflow.datacenter.meta.support;

import cn.hutool.core.util.StrUtil;
import org.springframework.stereotype.Component;
import tech.easyflow.datacenter.meta.entity.DatacenterSource;
import tech.easyflow.datacenter.meta.enums.DatacenterSourceType;

import java.util.LinkedHashMap;
import java.util.Map;

@Component
public class DatacenterSourceConnectionDefaults {

    public boolean supportsExternalConnection(String sourceType) {
        if (StrUtil.isBlank(sourceType)) {
            return false;
        }
        DatacenterSourceType resolved = resolveSourceType(sourceType);
        if (resolved == null) {
            return false;
        }
        return switch (resolved) {
            case MYSQL, POSTGRESQL, ORACLE, GAUSSDB_NATIVE, GBASE_8A, GBASE_8S -> true;
            default -> false;
        };
    }

    public DatacenterSource normalize(DatacenterSource source) {
        if (source == null || !supportsExternalConnection(source.getSourceType())) {
            return source;
        }
        if (source.getPort() == null || source.getPort() <= 0) {
            source.setPort(defaultPort(source.getSourceType()));
        }
        if (StrUtil.isBlank(source.getDriverClassName())) {
            source.setDriverClassName(defaultDriverClassName(source.getSourceType()));
        }
        if (StrUtil.isBlank(source.getJdbcUrl())) {
            String jdbcUrl = buildJdbcUrl(source);
            if (StrUtil.isNotBlank(jdbcUrl)) {
                source.setJdbcUrl(jdbcUrl);
            }
        }
        return source;
    }

    public Map<String, Object> sanitizeConfig(Map<String, Object> configJson) {
        Map<String, Object> sanitized = new LinkedHashMap<>();
        if (configJson == null || configJson.isEmpty()) {
            return sanitized;
        }
        sanitized.putAll(configJson);
        sanitized.remove("password");
        return sanitized;
    }

    public Integer defaultPort(String sourceType) {
        DatacenterSourceType resolved = requireSourceType(sourceType);
        return switch (resolved) {
            case MYSQL -> 3306;
            case POSTGRESQL, GAUSSDB_NATIVE -> 5432;
            case ORACLE -> 1521;
            case GBASE_8A -> 5258;
            case GBASE_8S -> 9088;
            default -> null;
        };
    }

    public String defaultDriverClassName(String sourceType) {
        DatacenterSourceType resolved = requireSourceType(sourceType);
        return switch (resolved) {
            case MYSQL -> "com.mysql.cj.jdbc.Driver";
            case POSTGRESQL, GAUSSDB_NATIVE -> "org.postgresql.Driver";
            case ORACLE -> "oracle.jdbc.OracleDriver";
            case GBASE_8A -> "com.gbase.jdbc.Driver";
            case GBASE_8S -> "com.gbasedbt.jdbc.Driver";
            default -> "";
        };
    }

    public String buildJdbcUrl(DatacenterSource source) {
        if (source == null || !supportsExternalConnection(source.getSourceType())) {
            return null;
        }
        String host = StrUtil.trimToEmpty(source.getHost());
        Integer port = source.getPort() == null || source.getPort() <= 0 ? defaultPort(source.getSourceType()) : source.getPort();
        String databaseName = resolveDatabaseName(source);
        if (StrUtil.isBlank(host) || port == null || StrUtil.isBlank(databaseName)) {
            return null;
        }
        DatacenterSourceType resolved = requireSourceType(source.getSourceType());
        return switch (resolved) {
            case MYSQL -> String.format(
                    "jdbc:mysql://%s:%d/%s?useUnicode=true&characterEncoding=utf-8&serverTimezone=Asia/Shanghai&useSSL=false",
                    host, port, databaseName
            );
            case POSTGRESQL -> String.format("jdbc:postgresql://%s:%d/%s", host, port, databaseName);
            case ORACLE -> String.format("jdbc:oracle:thin:@//%s:%d/%s", host, port, databaseName);
            case GAUSSDB_NATIVE -> String.format("jdbc:postgresql://%s:%d/%s", host, port, databaseName);
            case GBASE_8A -> String.format("jdbc:gbase://%s:%d/%s", host, port, databaseName);
            case GBASE_8S -> {
                String informixServer = resolveInformixServer(source);
                if (StrUtil.isBlank(informixServer)) {
                    yield null;
                }
                yield String.format("jdbc:gbasedbt-sqli://%s:%d/%s:INFORMIXSERVER=%s", host, port, databaseName, informixServer);
            }
            default -> null;
        };
    }

    private DatacenterSourceType requireSourceType(String sourceType) {
        DatacenterSourceType resolved = resolveSourceType(sourceType);
        if (resolved == null) {
            throw new IllegalArgumentException("Unsupported datacenter source type: " + sourceType);
        }
        return resolved;
    }

    private DatacenterSourceType resolveSourceType(String sourceType) {
        try {
            return DatacenterSourceType.valueOf(sourceType);
        } catch (IllegalArgumentException ex) {
            return null;
        }
    }

    private String resolveDatabaseName(DatacenterSource source) {
        if (StrUtil.isNotBlank(source.getDatabaseName())) {
            return source.getDatabaseName().trim();
        }
        if (source.getConfigJson() == null) {
            return null;
        }
        Object serviceName = source.getConfigJson().get("serviceName");
        if (serviceName != null && StrUtil.isNotBlank(String.valueOf(serviceName))) {
            return String.valueOf(serviceName).trim();
        }
        return null;
    }

    private String resolveInformixServer(DatacenterSource source) {
        if (source.getConfigJson() == null) {
            return null;
        }
        Object informixServer = source.getConfigJson().get("informixServer");
        if (informixServer == null) {
            return null;
        }
        String value = String.valueOf(informixServer).trim();
        return value.isEmpty() ? null : value;
    }
}
