package com.ruoyi.framework.config;

import java.io.FileInputStream;
import java.io.IOException;
import java.util.*;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.sql.DataSource;

import com.ruoyi.common.core.page.TableDataInfo;
import com.ruoyi.common.utils.StringUtils;
import com.ruoyi.druid.service.IDruidConfigService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import com.alibaba.druid.pool.DruidDataSource;
import com.alibaba.druid.spring.boot.autoconfigure.DruidDataSourceBuilder;
import com.alibaba.druid.spring.boot.autoconfigure.properties.DruidStatProperties;
import com.alibaba.druid.util.Utils;
import com.ruoyi.common.enums.DataSourceType;
import com.ruoyi.common.utils.spring.SpringUtils;
import com.ruoyi.framework.config.properties.DruidProperties;
import com.ruoyi.framework.datasource.DynamicDataSource;
import org.springframework.stereotype.Component;
import org.yaml.snakeyaml.DumperOptions;
import org.yaml.snakeyaml.Yaml;

/**
 * druid 配置多数据源
 *
 * @author ruoyi
 */
@Configuration
public class DruidConfig
{
    @Bean
    @ConfigurationProperties("spring.datasource.druid.master")
    public DataSource masterDataSource(DruidProperties druidProperties)
    {
        DruidDataSource dataSource = DruidDataSourceBuilder.create().build();
        return druidProperties.dataSource(dataSource);
    }

    /*@Bean
    @ConfigurationProperties("spring.datasource.druid.slave")
    @ConditionalOnProperty(prefix = "spring.datasource.druid.slave", name = "enabled", havingValue = "true")
    public DataSource slaveDataSource(DruidProperties druidProperties)
    {
        //DruidDataSource dataSource = DruidDataSourceBuilder.create().build();
        DruidDataSource druidDataSource = new DruidDataSource();
        List<com.ruoyi.druid.domain.DruidConfig> list = getList();
        for (com.ruoyi.druid.domain.DruidConfig config: list) {
            if(config.getPropertyName().equalsIgnoreCase("slave")) {
                String url = "jdbc:" + config.getType() + "://" + config.getHost() + ":" + config.getPort() + "/" + config.getDataBase();

                Properties properties = new Properties();
                properties.setProperty("password", config.getPassword());
                properties.setProperty("username", config.getUser());
                properties.setProperty("driverClassName", config.getDriverClass());
                properties.setProperty("url", url);

                druidDataSource.setConnectProperties(properties);
            }
        }
        return druidProperties.dataSource(druidDataSource);
    }*/

    private com.ruoyi.druid.domain.DruidConfig urlSplit(String url, String type) {
        com.ruoyi.druid.domain.DruidConfig druidConfig = new com.ruoyi.druid.domain.DruidConfig();
        if(StringUtils.equals(type, "MySQL") || StringUtils.equals(type, "PostgreSQL")) {//jdbc:mysql://localhost:3306/dataCenter
            if(url.contains("?")) {
                druidConfig.setDataBase(url.substring(url.lastIndexOf("/")+1, url.indexOf("?")));
            } else {
                druidConfig.setDataBase(url.substring(url.lastIndexOf("/")+1));
            }
            druidConfig.setHost(url.substring(url.indexOf("://")+3, url.lastIndexOf(":")));
            druidConfig.setPort(url.substring(url.lastIndexOf(":")+1, url.lastIndexOf("/")));
        }
        else if(StringUtils.equals(type, "SQLServer")) {//jdbc:sqlserver://localhost:7777;database=sqlserver
            druidConfig.setDataBase(url.substring(url.lastIndexOf("database=")+9, url.indexOf(";encrypt")));
            druidConfig.setHost(url.substring(url.indexOf("://")+3, url.lastIndexOf(":")));
            druidConfig.setPort(url.substring(url.lastIndexOf(":")+1, url.indexOf(";database=")));
        }
        else if(StringUtils.equals(type, "Oracle")) {//jdbc:oracle:thin:@localhost:1521:oracle
            String str = url.substring(url.indexOf(":@")+2);
            druidConfig.setDataBase(str.substring(str.lastIndexOf(":")+1));
            druidConfig.setHost(str.substring(0,str.indexOf(":")));
            druidConfig.setPort(str.substring(str.indexOf(":")+1, str.lastIndexOf(":")));
        }

        return druidConfig;
    }
    private String getUrl(com.ruoyi.druid.domain.DruidConfig druidConfig) {
        String url = "";
        if(StringUtils.equals(druidConfig.getType(), "MySQL")) {//jdbc:mysql://localhost:3306/dataCenter
            url = "jdbc:mysql://"+druidConfig.getHost()+":"+druidConfig.getPort()+"/"+druidConfig.getDataBase();
        }
        else if(StringUtils.equals(druidConfig.getType(), "SQLServer")) {//jdbc:sqlserver://localhost:7777;database=sqlserver
            url = "jdbc:sqlserver://"+druidConfig.getHost()+":"+druidConfig.getPort()+";database="+druidConfig.getDataBase()+";encrypt=true;trustServerCertificate=true;";
        }
        else if(StringUtils.equals(druidConfig.getType(), "Oracle")) {//jdbc:oracle:thin:@localhost:1521:oracle
            url = "jdbc:oracle:thin:@"+druidConfig.getHost()+":"+druidConfig.getPort()+":"+druidConfig.getDataBase();
        }
        else if(StringUtils.equals(druidConfig.getType(), "PostgreSQL")) {//jdbc:postgresql://localhost:5432/postgres
            url = "jdbc:postgresql://"+druidConfig.getHost()+":"+druidConfig.getPort()+"/"+druidConfig.getDataBase();
        }

        return url;
    }

    public List<com.ruoyi.druid.domain.DruidConfig> getList()
    {
        try {
            // 读取YAML文件
            //D:\langhengcode\DataCenter\ruoyi-admin\src\main\resources\application-druid.yml
            String path = "D:\\langhengcode\\DataCenter\\ruoyi-admin\\src\\main\\resources\\application-druid.yml";
            FileInputStream fis = new FileInputStream(path);

            DumperOptions options = new DumperOptions();
            options.setIndent(4);
            options.setDefaultFlowStyle(DumperOptions.FlowStyle.BLOCK);
            Yaml yaml = new Yaml(options);
            Map<String, Object> config = yaml.load(fis);

            Map<String, Object> spring = (Map) config.get("spring");
            Map<String, Object> datasource = (Map) spring.get("datasource");
            Map<String, Object> druid = (Map) datasource.get("druid");

            List<com.ruoyi.druid.domain.DruidConfig> list = new ArrayList<>();
            for (Map.Entry<String, Object> entry : druid.entrySet()) {
                String propertyName = entry.getKey();
                Map<String, Object> map = (Map) entry.getValue();

                String url = map.get("url").toString();
                com.ruoyi.druid.domain.DruidConfig druidConfig = urlSplit(url, String.valueOf(map.get("type")));

                druidConfig.setPropertyName(propertyName);
                druidConfig.setType(String.valueOf(map.get("type")));
                druidConfig.setVersion(String.valueOf(map.get("version")));
                druidConfig.setDriverClass(String.valueOf(map.get("driverClassName")));
                druidConfig.setUser(String.valueOf(map.get("username")));
                druidConfig.setPassword(String.valueOf(map.get("password")));
                druidConfig.setEnabled((Boolean) map.get("enabled"));

                list.add(druidConfig);
            }

            fis.close();
            return list;
        } catch (IOException e) {
            e.printStackTrace();
            return null;
        }
    }

    @Bean(name = "dynamicDataSource")
    @Primary
    public DynamicDataSource dataSource(DataSource masterDataSource)
    {
        Map<Object, Object> targetDataSources = new HashMap<>();
        targetDataSources.put(DataSourceType.MASTER.name(), masterDataSource);

        List<com.ruoyi.druid.domain.DruidConfig> list = getList();
        list.removeIf(e -> StringUtils.equals(e.getPropertyName(), "master"));
        for (com.ruoyi.druid.domain.DruidConfig config: list) {

            String url = getUrl(config);
            DruidDataSource druidDataSource = DruidDataSourceBuilder.create().build();

            druidDataSource.setUsername(config.getUser());
            druidDataSource.setPassword(config.getPassword());
            druidDataSource.setUrl(url);
            druidDataSource.setDriverClassName(config.getDriverClass());

            if(StringUtils.equals(config.getType(), "MySQL")) {
                targetDataSources.put(DataSourceType.SLAVE.name(), druidDataSource);
            }
            else if(StringUtils.equals(config.getType(), "SQLServer")) {
                targetDataSources.put(DataSourceType.SQLSERVER.name(), druidDataSource);
            }
            else if(StringUtils.equals(config.getType(), "Oracle")) {
                targetDataSources.put(DataSourceType.ORACLE.name(), druidDataSource);
            }
            else if(StringUtils.equals(config.getType(), "PostgreSQL")) {
                targetDataSources.put(DataSourceType.PGSQL.name(), druidDataSource);
            }

        }

        //setDataSource(targetDataSources, DataSourceType.SLAVE.name(), "slaveDataSource");

        return new DynamicDataSource(masterDataSource, targetDataSources);
    }

    /**
     * 设置数据源
     *
     * @param targetDataSources 备选数据源集合
     * @param sourceName 数据源名称
     * @param beanName bean名称
     */
    public void setDataSource(Map<Object, Object> targetDataSources, String sourceName, String beanName)
    {
        try
        {
            DataSource dataSource = SpringUtils.getBean(beanName);
            targetDataSources.put(sourceName, dataSource);
        }
        catch (Exception e)
        {
        }
    }

    /**
     * 去除监控页面底部的广告
     */
    @SuppressWarnings({ "rawtypes", "unchecked" })
    @Bean
    @ConditionalOnProperty(name = "spring.datasource.druid.statViewServlet.enabled", havingValue = "true")
    public FilterRegistrationBean removeDruidFilterRegistrationBean(DruidStatProperties properties)
    {
        // 获取web监控页面的参数
        DruidStatProperties.StatViewServlet config = properties.getStatViewServlet();
        // 提取common.js的配置路径
        String pattern = config.getUrlPattern() != null ? config.getUrlPattern() : "/druid/*";
        String commonJsPattern = pattern.replaceAll("\\*", "js/common.js");
        final String filePath = "support/http/resources/js/common.js";
        // 创建filter进行过滤
        Filter filter = new Filter()
        {
            @Override
            public void init(javax.servlet.FilterConfig filterConfig) throws ServletException
            {
            }
            @Override
            public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
                    throws IOException, ServletException
            {
                chain.doFilter(request, response);
                // 重置缓冲区，响应头不会被重置
                response.resetBuffer();
                // 获取common.js
                String text = Utils.readFromResource(filePath);
                // 正则替换banner, 除去底部的广告信息
                text = text.replaceAll("<a.*?banner\"></a><br/>", "");
                text = text.replaceAll("powered.*?shrek.wang</a>", "");
                response.getWriter().write(text);
            }
            @Override
            public void destroy()
            {
            }
        };
        FilterRegistrationBean registrationBean = new FilterRegistrationBean();
        registrationBean.setFilter(filter);
        registrationBean.addUrlPatterns(commonJsPattern);
        return registrationBean;
    }
}
