package com.hzya.frame.webapp.web.aop;

import com.alibaba.druid.pool.DruidDataSource;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.dynamic.datasource.DynamicRoutingDataSource;
import com.baomidou.dynamic.datasource.annotation.DS;
import com.baomidou.dynamic.datasource.exception.CannotFindDataSourceException;
import com.hzya.frame.datasource.DataSourceUtilProperties;
import com.hzya.frame.sysnew.application.database.dao.ISysApplicationDatabaseDao;
import com.hzya.frame.sysnew.application.database.entity.SysApplicationDatabaseEntity;
import com.hzya.frame.util.AESUtil;
import com.hzya.frame.web.entity.BaseEntity;
import com.hzya.frame.web.exception.BaseSystemException;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import javax.sql.DataSource;
import java.sql.Connection;
import java.sql.DriverManager;
import java.util.List;

/**
 * @author 👻👻👻👻👻👻👻👻👻👻 gjh
 * @version 1.0
 * @content
 * @date 2023-10-09 11:50
 */
@Aspect
@Component
public class AopDynamicRoutingDataSourceInit {
    private final Logger logger = LoggerFactory.getLogger(this.getClass());
    @Resource
    private DataSource dataSource;
    @Resource
    private ISysApplicationDatabaseDao sysApplicationDatabaseDao;


    @Before("@annotation(dsAnnotation)")
    public void beforeDynamicRoutingDataSourceInitMethod(JoinPoint joinPoint, DS dsAnnotation) {
        //logger.info("beforeDynamicRoutingDataSourceInitMethod:拦截所有使用ds注解的方法，根据ds的value值初始化数据源！");
        String dsValue = dsAnnotation.value();
        if (dsValue != null && !"".equals(dsValue) && dsValue.contains("#")) {
            Object[] args = joinPoint.getArgs();
            if (args.length > 0) {
                for (int i = 0; i < args.length; i++) {
                    Object arg = args[i];
                    if (arg instanceof BaseEntity) {
                        BaseEntity baseEntity = (BaseEntity) arg;
                        dsValue = baseEntity.getDataSourceCode();
                    }
                }
            }
        }
        logger.info("beforeDynamicRoutingDataSourceInitMethod DS.value:" + dsValue);
        DynamicRoutingDataSource ds = (DynamicRoutingDataSource) dataSource;
        DataSource dsDatasource = null;
        try {
            dsDatasource = ds.getDataSource(dsValue);
        } catch (CannotFindDataSourceException exception) {
            //logger.info("beforeDynamicRoutingDataSourceInitMethod:根据ds获取dsDatasource失败！异常信息：" + "exception.getMessage()" + " 执行初始化数据源：" + dsValue);
            SysApplicationDatabaseEntity entity = new SysApplicationDatabaseEntity();
            entity.setSts("Y");
            entity.setDbStatus("1");
            entity.setSourceCode(dsValue);
            entity.setDataSourceCode("master");
            List<SysApplicationDatabaseEntity> sysDataSourceEntities = sysApplicationDatabaseDao.queryDSBase(entity);
            //logger.info("beforeDynamicRoutingDataSourceInitMethod:根据dsValue获取数据源信息查询结果 sysDataSourceEntities.size:" + sysDataSourceEntities.size());
            if (sysDataSourceEntities != null && sysDataSourceEntities.size() > 0) {
                for (int i = 0; i < sysDataSourceEntities.size(); i++) {
                    JSONObject defaultDataSourceProperties = new JSONObject();
                    defaultDataSourceProperties.put("datasource_code", sysDataSourceEntities.get(i).getSourceCode());
                    defaultDataSourceProperties.put("source_url", sysDataSourceEntities.get(i).getSourceUrl());
                    defaultDataSourceProperties.put("source_type", sysDataSourceEntities.get(i).getSourceTypeName());
                    defaultDataSourceProperties.put("login_name", sysDataSourceEntities.get(i).getLoginName());
                    defaultDataSourceProperties.put("password", AESUtil.decrypt(sysDataSourceEntities.get(i).getPassword()));
                    //defaultDataSourceProperties.put("password", sysDataSourceEntities.get(i).getPassword());
                    defaultDataSourceProperties.put("db_name", sysDataSourceEntities.get(i).getDbName());
                    try {
                        logger.info("***初始化数据源-{}：*********", sysDataSourceEntities.get(i).getSourceName());
                        DruidDataSource dataSource = createDefaultDataSource(defaultDataSourceProperties);
                        ds.addDataSource(sysDataSourceEntities.get(i).getSourceCode(), dataSource);
                        logger.info("***初始化数据源-{}成功：*********", sysDataSourceEntities.get(i).getSourceName());
                    } catch (Exception e) {
                        logger.info("***初始化数据源-{}失败：*********", sysDataSourceEntities.get(i).getSourceName());
                        logger.info(e.getMessage());
                    }
                }
            } else {
                logger.info("beforeDynamicRoutingDataSourceInitMethod:根据dsValue未获取数据源信息查询结果 抛出数据源初始化失败异常:" + dsValue);
                throw new BaseSystemException("根据dsValue: " + dsValue + " 未能初始化成功数据源！请检查数据源信息！");
            }
        }
    }

    private DruidDataSource createDefaultDataSource(JSONObject defaultDataSourceProperties) throws RuntimeException {
        //根据datasource_code查询数据源配置信息
        String datasource_code = String.valueOf(defaultDataSourceProperties.get("datasource_code"));
        String source_url = String.valueOf(defaultDataSourceProperties.get("source_url"));
        String login_name = String.valueOf(defaultDataSourceProperties.get("login_name"));
        String password = String.valueOf(defaultDataSourceProperties.get("password"));
        String db_name = String.valueOf(defaultDataSourceProperties.get("db_name"));
        String source_type = String.valueOf(defaultDataSourceProperties.get("source_type"));
        if (defaultDataSourceProperties != null) {
            String driveClass = "";
            if ("mysql".equalsIgnoreCase(source_type)) {
                driveClass = DataSourceUtilProperties.MYSQLDRIVER_6;
            } else if ("oracle".equalsIgnoreCase(source_type)) {
                driveClass = DataSourceUtilProperties.ORACLEDRIVER;
            } else if ("sqlserver2000".equalsIgnoreCase(source_type)) {
                driveClass = DataSourceUtilProperties.SQL2000DRIVER;
            } else if ("sqlServer".equalsIgnoreCase(source_type)) {
                driveClass = DataSourceUtilProperties.SQL2005DRIVER;
            }
            else if ("dm".equalsIgnoreCase(source_type)) {
                driveClass = DataSourceUtilProperties.dm;
            }
            try {
                //测试连接
                Class.forName(driveClass);
                Connection connection = DriverManager.getConnection(source_url, login_name, password);// 相当于连接数据库
                if (connection != null) {
                    //初始化数据源信息
                    DruidDataSource druidDataSource = new DruidDataSource();
                    druidDataSource.setUrl(source_url);
                    druidDataSource.setUsername(login_name);
                    druidDataSource.setPassword(password);
                    druidDataSource.setName(db_name);
                    druidDataSource.setDriverClassName(driveClass);
                    druidDataSource.setInitialSize(5);
                    druidDataSource.setMinIdle(5);
                    druidDataSource.setMaxActive(100);
                    druidDataSource.setMaxWait(60000);
                    druidDataSource.setTimeBetweenEvictionRunsMillis(60000);
                    druidDataSource.setMinEvictableIdleTimeMillis(300000);
                    druidDataSource.setMaxEvictableIdleTimeMillis(600000);
                    if ("oracle".equals(source_type)) {
                        druidDataSource.setValidationQuery("select 1 from dual");
                    } else {
                        druidDataSource.setValidationQuery("SELECT 1");
                    }
                    druidDataSource.setTestWhileIdle(true);
                    druidDataSource.setTestOnBorrow(false);
                    druidDataSource.setTestOnReturn(false);
                    druidDataSource.setPoolPreparedStatements(true);
                    druidDataSource.setMaxPoolPreparedStatementPerConnectionSize(20);
                    druidDataSource.setRemoveAbandoned(true);
                    druidDataSource.setRemoveAbandonedTimeout(999999);
                    druidDataSource.init();
                    return druidDataSource;
                } else {
                    throw new RuntimeException("测试默认数据库连接失败datasource_code：" + datasource_code);
                }
            } catch (Exception e) {
                logger.info("==================创建数据源失败===================");
                throw new RuntimeException("创建数据源失败" + e.getMessage());
            }


        } else {
            throw new RuntimeException("source_code:" + datasource_code + "不存在");
        }
    }

}
