/**
 * @ProjectName: 智慧评标-主观分助手
 * @Package: com.zhpb.gdyd_zhpb_zgf.config
 * @ClassName: DataSourceConfig
 * @Description: 数据源配置类，配置MySQL和PostgreSQL双数据源，支持数据库自动创建
 * @Author: 张志锋
 * @Date: 2025-10-31
 * @Version: 1.0
 * @Copyright: © 2025 智慧评标-主观分助手
 */
package com.zhpb.gdyd_zhpb_zgf.config;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.boot.jdbc.DataSourceBuilder;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import org.springframework.core.env.Environment;
import org.springframework.data.jpa.repository.config.EnableJpaRepositories;
import org.springframework.orm.jpa.JpaTransactionManager;
import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean;
import org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.annotation.EnableTransactionManagement;

import javax.sql.DataSource;
import java.util.Properties;

@Configuration
@EnableTransactionManagement
@EnableJpaRepositories(basePackages = "com.zhpb.gdyd_zhpb_zgf.repository")
public class DataSourceConfig {

    private static final Logger LOGGER = LoggerFactory.getLogger(DataSourceConfig.class);

    private final Environment environment;

    public DataSourceConfig(Environment environment) {
        this.environment = environment;
    }

    @Bean
    @Primary
    public DataSource dataSource() {
        ensurePostgreSQLDatabase();

        DataSource dataSource = DataSourceBuilder.create()
                .driverClassName(environment.getProperty("spring.datasource.driver-class-name"))
                .url(environment.getProperty("spring.datasource.url"))
                .username(environment.getProperty("spring.datasource.username"))
                .password(environment.getProperty("spring.datasource.password"))
                .build();

        ensurePostgreSQLVectorExtension();
        return dataSource;
    }

    @Bean
    @Primary
    public LocalContainerEntityManagerFactoryBean entityManagerFactory(DataSource dataSource) {
        LocalContainerEntityManagerFactoryBean em = new LocalContainerEntityManagerFactoryBean();
        em.setDataSource(dataSource);
        em.setPackagesToScan("com.zhpb.gdyd_zhpb_zgf.entity");

        HibernateJpaVendorAdapter vendorAdapter = new HibernateJpaVendorAdapter();
        vendorAdapter.setShowSql(Boolean.parseBoolean(environment.getProperty("spring.jpa.show-sql", "false")));
        em.setJpaVendorAdapter(vendorAdapter);

        Properties properties = new Properties();
        properties.setProperty("hibernate.hbm2ddl.auto",
                environment.getProperty("spring.jpa.hibernate.ddl-auto", "update"));
        properties.setProperty("hibernate.dialect",
                environment.getProperty("spring.jpa.properties.hibernate.dialect",
                        "org.hibernate.dialect.PostgreSQLDialect"));
        properties.setProperty("hibernate.format_sql",
                environment.getProperty("spring.jpa.properties.hibernate.format_sql", "false"));
        properties.setProperty("hibernate.jdbc.time_zone",
                environment.getProperty("spring.jpa.properties.hibernate.jdbc.time_zone", "Asia/Shanghai"));
        em.setJpaProperties(properties);

        return em;
    }

    @Bean
    @Primary
    public PlatformTransactionManager transactionManager(
            LocalContainerEntityManagerFactoryBean entityManagerFactory) {
        return new JpaTransactionManager(entityManagerFactory.getObject());
    }

    private void ensurePostgreSQLVectorExtension() {
        try {
            String url = environment.getProperty("spring.datasource.url");
            String username = environment.getProperty("spring.datasource.username", "postgres");
            String password = environment.getProperty("spring.datasource.password", "123456");

            if (url == null) {
                return;
            }

            try (java.sql.Connection conn = java.sql.DriverManager.getConnection(url, username, password);
                 java.sql.Statement stmt = conn.createStatement()) {

                stmt.execute("CREATE EXTENSION IF NOT EXISTS vector");

                try (java.sql.ResultSet rs = stmt.executeQuery(
                        "SELECT EXISTS (SELECT FROM information_schema.tables WHERE table_name = 't_pdf_vector')")) {
                    if (rs.next() && !rs.getBoolean(1)) {
                        stmt.execute("CREATE TABLE t_pdf_vector (" +
                                "id BIGSERIAL PRIMARY KEY, " +
                                "file_path VARCHAR(1000) NOT NULL, " +
                                "file_name VARCHAR(500) NOT NULL, " +
                                "content TEXT, " +
                                "vector vector, " +
                                "dimension INTEGER NOT NULL, " +
                                "file_id VARCHAR(64), " +
                                "project_id VARCHAR(100), " +
                                "supplier_id VARCHAR(64), " +
                                "file_type_id BIGINT, " +
                                "create_time TIMESTAMP(6) NOT NULL DEFAULT NOW(), " +
                                "update_time TIMESTAMP(6) DEFAULT NOW()" +
                                ")");
                        LOGGER.info("PostgreSQL t_pdf_vector表已创建");
                    } else {
                        addMissingColumnsIfNeeded(stmt);
                    }
                }

                try (java.sql.ResultSet rs = stmt.executeQuery(
                        "SELECT EXISTS (SELECT FROM information_schema.tables WHERE table_name = 't_product')")) {
                    if (rs.next() && !rs.getBoolean(1)) {
                        stmt.execute("CREATE TABLE t_product (" +
                                "id BIGSERIAL PRIMARY KEY, " +
                                "name VARCHAR(255), " +
                                "price DOUBLE PRECISION" +
                                ")");
                        LOGGER.info("PostgreSQL t_product表已创建");
                    }
                }

                LOGGER.debug("PostgreSQL pgvector扩展和表初始化完成");
            }
        } catch (Exception e) {
            LOGGER.warn("创建PostgreSQL pgvector扩展或表失败: {}", e.getMessage());
        }
    }

    private void addMissingColumnsIfNeeded(java.sql.Statement stmt) {
        try {
            try (java.sql.ResultSet rs = stmt.executeQuery(
                    "SELECT EXISTS (SELECT 1 FROM information_schema.columns " +
                            "WHERE table_schema = 'public' AND table_name = 't_pdf_vector' AND column_name = 'file_id')")) {
                if (rs.next() && !rs.getBoolean(1)) {
                    stmt.execute("ALTER TABLE t_pdf_vector ADD COLUMN file_id VARCHAR(64)");
                    LOGGER.info("已添加file_id列到t_pdf_vector表");
                }
            }

            try (java.sql.ResultSet rs = stmt.executeQuery(
                    "SELECT EXISTS (SELECT 1 FROM information_schema.columns " +
                            "WHERE table_schema = 'public' AND table_name = 't_pdf_vector' AND column_name = 'supplier_id')")) {
                if (rs.next() && !rs.getBoolean(1)) {
                    stmt.execute("ALTER TABLE t_pdf_vector ADD COLUMN supplier_id VARCHAR(64)");
                    LOGGER.info("已添加supplier_id列到t_pdf_vector表");
                }
            }

            try (java.sql.ResultSet rs = stmt.executeQuery(
                    "SELECT EXISTS (SELECT 1 FROM information_schema.columns " +
                            "WHERE table_schema = 'public' AND table_name = 't_pdf_vector' AND column_name = 'file_type_id')")) {
                if (rs.next() && !rs.getBoolean(1)) {
                    stmt.execute("ALTER TABLE t_pdf_vector ADD COLUMN file_type_id BIGINT");
                    LOGGER.info("已添加file_type_id列到t_pdf_vector表");
                }
            }

            LOGGER.info("t_pdf_vector表字段检查完成");
        } catch (Exception e) {
            LOGGER.error("添加缺失列失败: {}", e.getMessage(), e);
        }
    }

    private void ensurePostgreSQLDatabase() {
        try {
            String url = environment.getProperty("spring.datasource.url");
            String username = environment.getProperty("spring.datasource.username", "postgres");
            String password = environment.getProperty("spring.datasource.password");

            if (url == null || password == null) {
                return;
            }

            String databaseName = extractDatabaseName(url);
            if (databaseName == null) {
                return;
            }

            String defaultUrl = url.replace("/" + databaseName, "/postgres");

            try (java.sql.Connection conn = java.sql.DriverManager.getConnection(defaultUrl, username, password)) {
                String checkSql = "SELECT 1 FROM pg_database WHERE datname = ?";
                try (java.sql.PreparedStatement stmt = conn.prepareStatement(checkSql)) {
                    stmt.setString(1, databaseName);
                    try (java.sql.ResultSet rs = stmt.executeQuery()) {
                        if (!rs.next()) {
                            conn.setAutoCommit(true);
                            String createSql = "CREATE DATABASE \"" + databaseName + "\"";
                            try (java.sql.Statement createStmt = conn.createStatement()) {
                                createStmt.execute(createSql);
                            }
                        }
                    }
                }
            }
        } catch (Exception e) {
            LOGGER.warn("自动创建PostgreSQL数据库失败: {}", e.getMessage());
        }
    }

    private String extractDatabaseName(String url) {
        if (url == null) {
            return null;
        }
        try {
            int lastSlash = url.lastIndexOf('/');
            if (lastSlash > 0 && lastSlash < url.length() - 1) {
                String dbPart = url.substring(lastSlash + 1);
                int questionMark = dbPart.indexOf('?');
                if (questionMark > 0) {
                    return dbPart.substring(0, questionMark);
                }
                return dbPart;
            }
        } catch (Exception ignored) {
        }
        return null;
    }
}

