package com.workiva.om.identity.configuration.persistence;

import com.mysql.cj.jdbc.MysqlDataSource;
import com.workiva.om.identity.configuration.properties.AwsWrapperProperties;
import com.workiva.om.identity.configuration.properties.MySqlProperties;
import com.zaxxer.hikari.HikariDataSource;
import java.util.Properties;
import software.amazon.jdbc.ds.AwsWrapperDataSource;

public class DataSourceBuilder {

    /**
     * Build a HikariDataSource that uses AwsWrapperDataSource as its underlying DataSource.
     *
     * @param command command object containing all necessary properties to build the data source
     * @return configured HikariDataSource
     */
    public static HikariDataSource buildAwsWrapperDataSource(ConfigureAwsWrapperDataSourceCommand command) {
        HikariDataSource ds = new HikariDataSource();
        ds.setUsername(command.getUsername());
        ds.setPassword(command.getPassword());
        if (command.getHikariProperties().getMaximumPoolSize() != null) {
            ds.setMaximumPoolSize(command.getHikariProperties().getMaximumPoolSize());
        }
        if (command.getHikariProperties().getMinimumIdle() != null) {
            ds.setMinimumIdle(command.getHikariProperties().getMinimumIdle());
        }
        if (command.getHikariProperties().getConnectionTimeout() != null) {
            ds.setConnectionTimeout(command.getHikariProperties().getConnectionTimeout());
        }
        if (command.getHikariProperties().getIdleTimeout() != null) {
            ds.setIdleTimeout(command.getHikariProperties().getIdleTimeout());
        }
        if (command.getHikariProperties().getMaxLifetime() != null) {
            ds.setMaxLifetime(command.getHikariProperties().getMaxLifetime());
        }
        if (command.getHikariProperties().getExceptionOverrideClassName() != null) {
            ds.setExceptionOverrideClassName(command.getHikariProperties().getExceptionOverrideClassName());
        }
        if (command.getHikariProperties().getAutoCommit() != null) {
            ds.setAutoCommit(command.getHikariProperties().getAutoCommit());
        }
        if (command.getHikariProperties().getPoolName() != null) {
            ds.setPoolName(command.getHikariProperties().getPoolName());
        }

        // https://github.com/aws/aws-advanced-jdbc-wrapper/blob/main/docs/using-the-jdbc-driver/DataSource.md#Using-the-AwsWrapperDataSource-with-Connection-Pooling-Frameworks
        ds.setDataSourceClassName(AwsWrapperDataSource.class.getName());
        ds.addDataSourceProperty("jdbcUrl", command.getJdbcUrl());
        ds.addDataSourceProperty("targetDataSourceClassName", MysqlDataSource.class.getName());
        ds.addDataSourceProperty(
            "targetDataSourceProperties",
            buildTargetProperties(command.getMySqlProperties(), command.getAwsWrapperProperties())
        );
        return ds;
    }

    /**
     * Build targetDataSourceProperties for AwsWrapperDataSource since it requires a pure java.util.Properties object.
     *
     * @param mySqlProperties properties for MySQL driver
     * @param awsWrapperProperties properties for AWS Advanced JDBC wrapper
     * @return Properties object containing both MySQL and AWS wrapper settings
     */
    private static Properties buildTargetProperties(
        MySqlProperties mySqlProperties,
        AwsWrapperProperties awsWrapperProperties
    ) {
        Properties props = new Properties();

        // Boolean and Integer props can be added directly;
        // Hikari and MySQL drivers will convert them correctly.
        if (mySqlProperties.getCachePrepStmts() != null) {
            props.put("cachePrepStmts", mySqlProperties.getCachePrepStmts());
        }
        if (mySqlProperties.getPrepStmtCacheSize() != null) {
            props.put("prepStmtCacheSize", mySqlProperties.getPrepStmtCacheSize());
        }
        if (mySqlProperties.getPrepStmtCacheSqlLimit() != null) {
            props.put("prepStmtCacheSqlLimit", mySqlProperties.getPrepStmtCacheSqlLimit());
        }
        if (mySqlProperties.getUseServerPrepStmts() != null) {
            props.put("useServerPrepStmts", mySqlProperties.getUseServerPrepStmts());
        }
        if (mySqlProperties.getRewriteBatchedStatements() != null) {
            props.put("rewriteBatchedStatements", mySqlProperties.getRewriteBatchedStatements());
        }
        if (mySqlProperties.getCacheServerConfiguration() != null) {
            props.put("cacheServerConfiguration", mySqlProperties.getCacheServerConfiguration());
        }
        if (mySqlProperties.getElideSetAutoCommits() != null) {
            props.put("elideSetAutoCommits", mySqlProperties.getElideSetAutoCommits());
        }
        if (mySqlProperties.getMaintainTimeStats() != null) {
            props.put("maintainTimeStats", mySqlProperties.getMaintainTimeStats());
        }
        if (mySqlProperties.getReadOnlyPropagatesToServer() != null) {
            props.put("readOnlyPropagatesToServer", mySqlProperties.getReadOnlyPropagatesToServer());
        }
        if (mySqlProperties.getTinyInt1isBit() != null) {
            props.put("tinyInt1isBit", mySqlProperties.getTinyInt1isBit());
        }
        if (mySqlProperties.getUseLocalSessionState() != null) {
            props.put("useLocalSessionState", mySqlProperties.getUseLocalSessionState());
        }
        if (mySqlProperties.getUseLocalTransactionState() != null) {
            props.put("useLocalTransactionState", mySqlProperties.getUseLocalTransactionState());
        }
        if (mySqlProperties.getCreateDatabaseIfNotExist() != null) {
            props.put("createDatabaseIfNotExist", mySqlProperties.getCreateDatabaseIfNotExist());
        }
        if (mySqlProperties.getOpenTelemetry() != null) props.put("openTelemetry", mySqlProperties.getOpenTelemetry());

        // AWS wrapper settings
        if (awsWrapperProperties.getWrapperDialect() != null) {
            props.put("wrapperDialect", awsWrapperProperties.getWrapperDialect());
        }
        if (awsWrapperProperties.getWrapperPlugins() != null) {
            props.put("wrapperPlugins", awsWrapperProperties.getWrapperPlugins());
        }

        return props;
    }
}
