package com.qiaoba.common.database.config;

import cn.hutool.core.collection.CollUtil;
import com.alibaba.druid.pool.DruidDataSource;
import com.qiaoba.common.base.constants.TenantConstant;
import com.qiaoba.common.base.context.BaseContext;
import com.qiaoba.common.base.enums.BaseEnum;
import com.qiaoba.common.database.constants.DynamicDatasourceConstant;
import com.qiaoba.common.database.entity.DynamicDataSource;
import com.qiaoba.common.database.properties.DataSourceProperties;
import com.qiaoba.common.database.service.DynamicDatasourceService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.annotation.Configuration;

import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;
import javax.annotation.Resource;
import java.sql.SQLException;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;

/**
 * 多数据源配置
 *
 * @author ailanyin
 * @version 1.0
 * @since 2021/10/15 0015 下午 16:43
 */
@Slf4j
@Configuration
public class DynamicDataSourceConfig {

    /**
     * Bean 必须叫 dataSource
     */
    @Resource
    private DynamicDataSourceContext dataSource;
    @Resource
    private DataSourceProperties dataSourceProperties;
    @Resource
    private DynamicDatasourceService dynamicDatasourceService;

    /**
     * 主要数据源
     */
    public static Map<Object, Object> PRIMARY_DATASOURCE_MAP = new ConcurrentHashMap<>();

    /**
     * 备用数据源-每次取0索引
     */
    public static Map<String, List<DynamicDataSource>> BACKUP_DATASOURCE_MAP = new ConcurrentHashMap<>();

    /**
     * 把DynamicDataSourceContext 纳入容器管理，其他地方使用DynamicDataSourceConfig 类可以直接从容器取对象，并调用freshDataSource方法
     */
    @PostConstruct
    public void init() {
        // 加载系统默认数据源
        initDefault();
        // 加载租户数据源
        initTenant();
    }

    private void initDefault() {
        List<DynamicDataSource> dataSources = dataSourceProperties.getDataSources();
        // 0索引作为主数据源
        addPrimaryMap(DynamicDatasourceConstant.MASTER_PREFIX + TenantConstant.DEFAULT_TENANT_ID, buildDataSource(dataSources.get(0)));
        dataSources.remove(0);
        // 非0索引的备用
        addBackupMap(TenantConstant.DEFAULT_TENANT_ID, dataSources);
        // 刷新数据源
        dataSource.freshDataSource(PRIMARY_DATASOURCE_MAP);
    }

    private void initTenant() {
        setDefaultSetting();
        Map<String, List<DynamicDataSource>> tenantDatasource = dynamicDatasourceService.loadAllTenantDatasource();
        for (String tenantId : tenantDatasource.keySet()) {
            List<DynamicDataSource> dataSources = tenantDatasource.get(tenantId);
            for (int i = 0; i < dataSources.size(); i++) {
                DynamicDataSource dynamicDataSource = dataSources.get(i);
                if (BaseEnum.YES.getCode().equals(dynamicDataSource.getIsPrimary())) {
                    addPrimaryMap(DynamicDatasourceConstant.MASTER_PREFIX + tenantId, buildDataSource(dataSources.get(i)));
                    // 去除主要数据源，剩下皆为备用数据源
                    dataSources.remove(i);
                }
            }
            // 备用数据源
            addBackupMap(tenantId, dataSources);
        }
        BaseContext.clearAllHolder();
        // 刷新数据源
        dataSource.freshDataSource(PRIMARY_DATASOURCE_MAP);
    }

    public void deleteTenantDataSource(String tenantId) {
        PRIMARY_DATASOURCE_MAP.remove(DynamicDatasourceConstant.MASTER_PREFIX + tenantId);
        dataSource.freshDataSource(PRIMARY_DATASOURCE_MAP);
    }

    private static Object buildDataSource(DynamicDataSource dynamicDataSource) {
        DruidDataSource dataSource = new DruidDataSource();
        dataSource.setUrl(dynamicDataSource.getUrl());
        dataSource.setUsername(dynamicDataSource.getUsername());
        dataSource.setPassword(dynamicDataSource.getPassword());
        dataSource.setDriverClassName(dynamicDataSource.getDriver());
        dataSource.setInitialSize(dynamicDataSource.getInitialSize());
        dataSource.setMinIdle(dynamicDataSource.getMinIdle());
        dataSource.setMaxActive(dynamicDataSource.getMaxActive());
        try {
            dataSource.init();
            return dataSource;
        } catch (SQLException e) {
            dataSource.close();
            return null;
        }
    }

    /**
     * 程序关闭后,要释放数据源连接池
     */
    @PreDestroy
    public void close() {
        Set<Map.Entry<Object, Object>> entries = PRIMARY_DATASOURCE_MAP.entrySet();
        for (Map.Entry<Object, Object> entry : entries) {
            DruidDataSource dataSource = (DruidDataSource) entry.getValue();
            dataSource.close();
        }
    }

    private void addPrimaryMap(String name, Object dataSource) {
        if (Objects.nonNull(dataSource)) {
            PRIMARY_DATASOURCE_MAP.put(name, dataSource);
        }
    }

    private void addBackupMap(String tenantId, List<DynamicDataSource> dataSources) {
        if (CollUtil.isNotEmpty(dataSources)) {
            BACKUP_DATASOURCE_MAP.put(tenantId, dataSources);
        }
    }

    private void handleDataSources(String tenantId, List<DynamicDataSource> dataSources) {


    }

    public void setDefaultSetting() {
        BaseContext.setDataSource(DynamicDatasourceConstant.MASTER_PREFIX + TenantConstant.DEFAULT_TENANT_ID);
        BaseContext.setTenantId(TenantConstant.DEFAULT_TENANT_ID);
    }
}
