package tech.easyflow.common.analyticaldb.config;

import com.zaxxer.hikari.HikariConfig;
import com.zaxxer.hikari.HikariDataSource;
import org.flywaydb.core.Flyway;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.util.StringUtils;
import tech.easyflow.common.analyticaldb.core.AnalyticalDBOperations;
import tech.easyflow.common.analyticaldb.core.DefaultAnalyticalDBOperations;

@Configuration
public class AnalyticalDBConfiguration {

    @Bean(destroyMethod = "close")
    @ConditionalOnProperty(prefix = "easyflow.analytical-db", name = "enabled", havingValue = "true")
    public AnalyticalDBResources analyticalDBResources(AnalyticalDBProperties properties) {
        HikariConfig config = new HikariConfig();
        config.setPoolName("easyflow-analytical-db");
        config.setDriverClassName(properties.getDriverClassName());
        config.setJdbcUrl(properties.getUrl());
        config.setUsername(properties.getUsername());
        config.setPassword(properties.getPassword());
        config.setMaximumPoolSize(properties.getPool().getMaxPoolSize());
        config.setMinimumIdle(properties.getPool().getMinIdle());
        config.setConnectionTimeout(properties.getPool().getConnectionTimeout());
        config.setValidationTimeout(properties.getPool().getValidationTimeout());
        config.setIdleTimeout(properties.getPool().getIdleTimeout());
        config.setMaxLifetime(properties.getPool().getMaxLifetime());
        config.setInitializationFailTimeout(-1L);
        HikariDataSource dataSource = new HikariDataSource(config);
        return new AnalyticalDBResources(dataSource, new JdbcTemplate(dataSource));
    }

    @Bean
    @ConditionalOnProperty(prefix = "easyflow.analytical-db", name = "enabled", havingValue = "true")
    public AnalyticalDBOperations analyticalDBOperations(AnalyticalDBResources resources) {
        return new DefaultAnalyticalDBOperations(resources.jdbcTemplate());
    }

    @Bean
    @ConditionalOnProperty(prefix = "easyflow.analytical-db", name = "enabled", havingValue = "true")
    public InitializingBean analyticalDBFlywayInitializer(AnalyticalDBResources resources,
                                                          AnalyticalDBFlywayProperties properties) {
        return () -> Flyway.configure()
                .dataSource(resources.dataSource())
                .locations(splitLocations(properties.getLocations()))
                .table(properties.getTable())
                .baselineOnMigrate(properties.isBaselineOnMigrate())
                .validateOnMigrate(properties.isValidateOnMigrate())
                .load()
                .migrate();
    }

    private String[] splitLocations(String locations) {
        if (!StringUtils.hasText(locations)) {
            return new String[]{"classpath:db/migration/analyticaldb"};
        }
        return StringUtils.commaDelimitedListToStringArray(locations);
    }

    public record AnalyticalDBResources(HikariDataSource dataSource, JdbcTemplate jdbcTemplate) implements AutoCloseable {

        @Override
        public void close() {
            dataSource.close();
        }
    }
}
