package gc.mda.signal_batch.global.config;

import com.zaxxer.hikari.HikariConfig;
import com.zaxxer.hikari.HikariDataSource;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import org.springframework.context.annotation.Profile;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;
import org.springframework.transaction.PlatformTransactionManager;

import javax.sql.DataSource;


@Slf4j
@Configuration
@Profile("local")
public class LocalDataSourceConfig {

    private final DataSourceConfigProperties properties;

    public LocalDataSourceConfig(DataSourceConfigProperties properties) {
        this.properties = properties;
    }

    @Bean
    @ConfigurationProperties(prefix = "spring.datasource.collect.hikari")
    public HikariConfig localCollectHikariConfig() {
        HikariConfig config = new HikariConfig();
        applyConnectionProps(config, properties.getCollect());
        config.setConnectionInitSql("SET TIME ZONE 'Asia/Seoul'; SET search_path TO signal, public;");
        return config;
    }

    @Bean
    public DataSource collectDataSource(@Qualifier("localCollectHikariConfig") HikariConfig hikariConfig) {
        HikariDataSource dataSource = new HikariDataSource(hikariConfig);
        log.info("Local Collect DataSource created: URL={}, poolSize={}", hikariConfig.getJdbcUrl(), hikariConfig.getMaximumPoolSize());
        return dataSource;
    }

    @Bean(name = "localQueryHikariConfig")
    @ConfigurationProperties(prefix = "spring.datasource.query.hikari")
    public HikariConfig localQueryHikariConfig() {
        HikariConfig config = new HikariConfig();
        applyConnectionProps(config, properties.getQuery());
        config.setConnectionInitSql("SET TIME ZONE 'Asia/Seoul'; SET search_path TO signal, public;");
        return config;
    }

    @Bean
    public DataSource queryDataSource(@Qualifier("localQueryHikariConfig") HikariConfig hikariConfig) {
        HikariDataSource dataSource = new HikariDataSource(hikariConfig);
        log.info("Local Query DataSource created: URL={}, poolSize={}", hikariConfig.getJdbcUrl(), hikariConfig.getMaximumPoolSize());
        return dataSource;
    }

    @Bean
    @ConfigurationProperties(prefix = "spring.datasource.batch.hikari")
    public HikariConfig localBatchHikariConfig() {
        HikariConfig config = new HikariConfig();
        applyConnectionProps(config, properties.getBatch());
        config.setConnectionInitSql("SET TIME ZONE 'Asia/Seoul'");
        return config;
    }

    @Bean
    @Primary
    public DataSource batchDataSource(@Qualifier("localBatchHikariConfig") HikariConfig hikariConfig) {
        HikariDataSource dataSource = new HikariDataSource(hikariConfig);
        log.info("Local Batch DataSource created: URL={}, poolSize={}", hikariConfig.getJdbcUrl(), hikariConfig.getMaximumPoolSize());
        return dataSource;
    }

    @Bean
    public DataSource dataSource(@Qualifier("batchDataSource") DataSource batchDataSource) {
        return batchDataSource;
    }

    @Bean
    public PlatformTransactionManager transactionManager(@Qualifier("collectDataSource") DataSource dataSource) {
        return new DataSourceTransactionManager(dataSource);
    }

    @Bean
    public PlatformTransactionManager queryTransactionManager(@Qualifier("queryDataSource") DataSource dataSource) {
        return new DataSourceTransactionManager(dataSource);
    }

    @Bean
    @Primary
    public PlatformTransactionManager batchTransactionManager(@Qualifier("batchDataSource") DataSource dataSource) {
        return new DataSourceTransactionManager(dataSource);
    }

    @Bean(name = "collectJdbcTemplate")
    public JdbcTemplate collectJdbcTemplate(@Qualifier("collectDataSource") DataSource dataSource) {
        JdbcTemplate jdbcTemplate = new JdbcTemplate(dataSource);
        jdbcTemplate.setFetchSize(10000);
        jdbcTemplate.setQueryTimeout(300);
        return jdbcTemplate;
    }

    @Bean(name = "queryJdbcTemplate")
    public JdbcTemplate queryJdbcTemplate(@Qualifier("queryDataSource") DataSource dataSource) {
        JdbcTemplate jdbcTemplate = new JdbcTemplate(dataSource);
        jdbcTemplate.setQueryTimeout(300);
        return jdbcTemplate;
    }

    @Bean(name = "collectNamedJdbcTemplate")
    public NamedParameterJdbcTemplate collectNamedJdbcTemplate(@Qualifier("collectDataSource") DataSource dataSource) {
        return new NamedParameterJdbcTemplate(dataSource);
    }

    @Bean(name = "queryNamedJdbcTemplate")
    public NamedParameterJdbcTemplate queryNamedJdbcTemplate(@Qualifier("queryDataSource") DataSource dataSource) {
        return new NamedParameterJdbcTemplate(dataSource);
    }

    private void applyConnectionProps(HikariConfig config, DataSourceConfigProperties.DatabaseProperties props) {
        config.setJdbcUrl(props.getJdbcUrl());
        config.setUsername(props.getUsername());
        config.setPassword(props.getPassword());
        config.setDriverClassName(props.getDriverClassName());
    }
}
