package net.northking.cctp.common.db.ds;

import com.zaxxer.hikari.HikariDataSource;
import org.springframework.boot.autoconfigure.jdbc.DataSourceProperties;
import org.springframework.jdbc.datasource.AbstractDataSource;
import org.springframework.util.StringUtils;

import javax.sql.DataSource;
import java.sql.Connection;
import java.sql.SQLException;
import java.util.HashMap;
import java.util.Map;

/**
 * 动态数据源，根据需求进行切换
 */
public class DynamicDataSource extends AbstractDataSource
{

  /**
   * 数据源集合
   */
  private static final Map<String, DataSource> DATA_SOURCE_MAP = new HashMap<>();

  /**
   * 默认的数据源
   */
  private static DataSource DEFAULT_DATA_SOURCE;

  /**
   * 动态数据源服务
   */
  private static DynamicDataSourceService dynamicDataSourceService;

  /**
   * 设置动态数据源服务
   *
   * @param service 动态数据源服务
   */
  public static void setDynamicDataSourceService(DynamicDataSourceService service)
  {
    DynamicDataSource.dynamicDataSourceService = service;
  }

  /**
   * 构造默认的数据源
   *
   * @param dataSource 默认数据源
   */
  public DynamicDataSource(DataSource dataSource)
  {
    DynamicDataSource.DEFAULT_DATA_SOURCE = dataSource;
  }

  /**
   * 创建新的数据源
   *
   * @param properties 数据源配置
   * @return 数据源
   */
  public synchronized static DataSource createDataSource(DataSourceProperties properties)
  {
    // 数据源名称
    String dsName = properties.getName();
    if (StringUtils.isEmpty(dsName))
    {
      throw new NullPointerException("数据源的名称不可为空。");
    }
    DataSource dataSource = DATA_SOURCE_MAP.get(dsName);

    if (dataSource == null)
    {
      HikariDataSource hikariDataSource = properties.initializeDataSourceBuilder().type(HikariDataSource.class).build();
      hikariDataSource.setPoolName(properties.getName());
      hikariDataSource.setMinimumIdle(1); // 最小连接数
      hikariDataSource.setMaximumPoolSize(5); // 最大连接数

      DATA_SOURCE_MAP.put(dsName, hikariDataSource);
      dataSource = hikariDataSource;
    }
    return dataSource;
  }

  /**
   * 根据名称获取数据源
   *
   * @param dataSourceName 数据源名称
   * @return 数据源
   */
  public static DataSource findDataSource(String dataSourceName)
  {
    if (StringUtils.isEmpty(dataSourceName))
    {
      return DEFAULT_DATA_SOURCE;
    }

    DataSource dataSource = DATA_SOURCE_MAP.get(dataSourceName);
    if (dataSource == null && dynamicDataSourceService != null)
    {
      DataSourceProperties properties = dynamicDataSourceService.findPropertiesById(dataSourceName);
      if (properties != null)
      {
        dataSource = createDataSource(properties);
      }
    }
    return dataSource;
  }

  /**
   * 获取指定的数据源
   *
   * @return 数据源
   */
  private DataSource lookupDataSource()
  {
    String dataSourceName = DynamicDataSourceContext.getDataSourceName();
    return findDataSource(dataSourceName);
  }

  /**
   * 移除数据源
   *
   * @param dataSourceId 数据源ID
   */
  public static void remove(String dataSourceId)
  {
    DataSource dataSource = DATA_SOURCE_MAP.get(dataSourceId);
    if (dataSource instanceof HikariDataSource)
    {
      HikariDataSource hikariDataSource = (HikariDataSource) dataSource;
      hikariDataSource.close();
    }
  }

  @Override
  public Connection getConnection() throws SQLException
  {
    DataSource dataSource = lookupDataSource();
    if (dataSource == null)
    {
      dataSource = DEFAULT_DATA_SOURCE;
    }
    logger.info("获取数据连接对象。");
    return dataSource.getConnection();
  }

  @Override
  public Connection getConnection(String username, String password) throws SQLException
  {
    DataSource dataSource = lookupDataSource();
    if (dataSource == null)
    {
      dataSource = DEFAULT_DATA_SOURCE;
    }
    return dataSource.getConnection(username, password);
  }

  public static Connection getConnection(String dataSourceId) throws SQLException
  {
    DataSource dataSource = findDataSource(dataSourceId);
    if (dataSource == null)
    {
      throw new SQLException("数据源不存在，ID=" + dataSourceId);
    } else
    {
      return dataSource.getConnection();
    }

  }
}
