package org.jeecg.modules.system.service.impl;

import com.baomidou.dynamic.datasource.DynamicRoutingDataSource;
import com.baomidou.dynamic.datasource.creator.DataSourceProperty;
import com.baomidou.dynamic.datasource.creator.druid.DruidDataSourceCreator;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.apache.commons.lang.StringUtils;
import org.jeecg.common.api.vo.Result;
import org.jeecg.common.util.dynamic.db.DataSourceCachePool;
import org.jeecg.common.util.oConvertUtils;
import org.jeecg.config.saas.DbUrlUtil;
import org.jeecg.modules.system.entity.SysDataSource;
import org.jeecg.modules.system.mapper.SysDataSourceMapper;
import org.jeecg.modules.system.service.ISysDataSourceService;
import org.jeecg.modules.system.util.SecurityUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import javax.sql.DataSource;
import java.io.IOException;
import java.sql.*;
import java.util.ArrayList;
import java.util.List;

/**
 * @Description: 多公司管理
 * @Author: jeecg-boot
 * @Date: 2019-12-25
 * @Version: V1.0
 */
@Service
public class SysDataSourceServiceImpl extends ServiceImpl<SysDataSourceMapper, SysDataSource> implements ISysDataSourceService {

    @Autowired
    private DruidDataSourceCreator dataSourceCreator;

    @Autowired
    private DataSource dataSource;
    @Resource
    private SysDataSourceMapper sysDataSourceMapper;

    @Override
//    public Result saveDataSource(SysDataSource sysDataSource) {
//        try {
//            long count = checkDbCode(sysDataSource.getCode());
//            if (count > 0) {
//                return Result.error("公司编号已存在");
//            }
//            String dbPassword = sysDataSource.getDbPassword();
//            if (StringUtils.isNotBlank(dbPassword)) {
//                String encrypt = SecurityUtil.jiami(dbPassword);
//                sysDataSource.setDbPassword(encrypt);
//            }
//            boolean result = save(sysDataSource);
//            if (result) {
//                //动态创建公司
//                addDynamicDataSource(sysDataSource, dbPassword);
//            }
//        } catch (Exception e) {
//            e.printStackTrace();
//        }
//        return Result.OK("添加成功！");
//    }
    public Result saveDataSource(SysDataSource sysDataSource) {
        try {
            // 校验数据库编码是否存在
            long count = sysDataSourceMapper.selectCount(
                    new LambdaQueryWrapper<SysDataSource>()
                            .eq(SysDataSource::getCode, sysDataSource.getCode())
            );
            if (count > 0) {
                return Result.error("公司编号已存在");
            }

            // 动态构造新 URL：替换 /host:port/之后到?之前的 dbName
            String dbUrl = sysDataSource.getDbUrl();
            String tenantCode = "n" + sysDataSource.getCode();
            String newDbUrl = dbUrl.replaceFirst("(?<=//[^/]+/)[^?]+", tenantCode);
            sysDataSource.setDbUrl(newDbUrl);
            System.out.println("新的 JDBC URL = " + newDbUrl);

            // 加密密码
            String plainPwd = sysDataSource.getDbPassword();
            if (StringUtils.isNotBlank(plainPwd)) {
                sysDataSource.setDbPassword(SecurityUtil.jiami(plainPwd));
            }

            // 保存数据源记录
            boolean saved = this.save(sysDataSource);
            if (saved) {
                // 查询模板数据源（如 code=10086）
                List<SysDataSource> templates = sysDataSourceMapper.selectList(
                        new LambdaQueryWrapper<SysDataSource>()
                                .eq(SysDataSource::getCode, "10086")
                );
                if (!templates.isEmpty()) {
                    for (SysDataSource tpl : templates) {
                        String srcUrl = tpl.getDbUrl();
                        String srcUser = tpl.getDbUsername();
                        String srcPwd = SecurityUtil.jiemi(tpl.getDbPassword());
                        String srcDbName = DbUrlUtil.extractDbName(srcUrl);
                        // 创建并复制所有表
                        copyAllTablesUsingJDBC(srcUrl, srcUser, srcPwd, srcDbName, tenantCode);
                    }
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
            return Result.error("添加公司失败");
        }
        return Result.OK("添加成功！");
    }

    /**
     * 使用 JDBC 来创建新数据库并复制所有表和数据
     *
     * @param dbUrl         源数据库的 JDBC URL（含库名），如 jdbc:mysql://host:3306/n10086?...
     * @param dbUsername    源库用户名
     * @param dbPassword    源库密码（已解密）
     * @param sourceDbName  源库名称 ("n10086")
     * @param newDbName     目标库名称（"n10095"）
     * @throws SQLException 如果任何 JDBC 操作失败
     */
    private void copyAllTablesUsingJDBC(
            String dbUrl, String dbUsername, String dbPassword,
            String sourceDbName, String newDbName) throws SQLException {

        // 1. 连接到已有的源库
        try (Connection conn = DriverManager.getConnection(dbUrl, dbUsername, dbPassword)) {

            // 2. 创建目标库（如果不存在）
            try (Statement stmtCreate = conn.createStatement()) {
                stmtCreate.executeUpdate("CREATE DATABASE IF NOT EXISTS " + newDbName);
            }

            // 3. 读取所有源库表名
            List<String> tables = new ArrayList<>();
            String fetchTablesSql =
                    "SELECT table_name FROM information_schema.tables " +
                            "WHERE table_schema = '" + sourceDbName + "'";
            try (Statement stmtFetch = conn.createStatement();
                 ResultSet rs = stmtFetch.executeQuery(fetchTablesSql)) {

                while (rs.next()) {
                    tables.add(rs.getString("table_name"));
                }
            }

            // 4. 对每个表：检查、建结构、复制数据
            try (Statement stmt = conn.createStatement()) {
                for (String tbl : tables) {
                    // 4.1 检查目标库中是否已存在此表
                    String checkSql =
                            "SELECT COUNT(*) FROM information_schema.tables " +
                                    "WHERE table_schema = '" + newDbName + "' " +
                                    "AND table_name = '" + tbl + "'";
                    try (ResultSet crs = stmt.executeQuery(checkSql)) {
                        crs.next();
                        if (crs.getInt(1) == 0) {
                            // 4.2 不存在就复制表结构
                            String createTableSql =
                                    "CREATE TABLE " + newDbName + "." + tbl +
                                            " LIKE " + sourceDbName + "." + tbl;
                            stmt.executeUpdate(createTableSql);
                        }
                    }

                    // 4.3 复制数据
                    String insertDataSql =
                            "INSERT INTO " + newDbName + "." + tbl +
                                    " SELECT * FROM " + sourceDbName + "." + tbl;
                    stmt.executeUpdate(insertDataSql);

                    // 3.3 如果是 sys_user 表，修改 admin 用户的 realname
                    if ("sys_user".equalsIgnoreCase(tbl)) {
                        // newDbName 形如 "n10399"，去掉首字母得到 "10399"
                        String suffix = newDbName.substring(1);
                        String updateSql =
                                "UPDATE " + newDbName + ".sys_user " +
                                        "SET realname = CONCAT(realname, '" + suffix + "') " +
                                        "WHERE username = 'admin'";
                        stmt.executeUpdate(updateSql);
                    }
                }
            }
        }
    }


    @Override
    public Result editDataSource(SysDataSource sysDataSource) {
        try {
            SysDataSource d = getById(sysDataSource.getId());
            DataSourceCachePool.removeCache(d.getCode());
            String dbPassword = sysDataSource.getDbPassword();
            if (StringUtils.isNotBlank(dbPassword)) {
                String encrypt = SecurityUtil.jiami(dbPassword);
                sysDataSource.setDbPassword(encrypt);
            }
            Boolean result = updateById(sysDataSource);
            if (result) {
                //先删除老的公司
                // removeDynamicDataSource(d.getCode());
                //添加新的公司
                //addDynamicDataSource(sysDataSource,dbPassword);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return Result.OK("编辑成功!");
    }

    @Override
    public Result deleteDataSource(String id) {
        SysDataSource sysDataSource = getById(id);
        String code = sysDataSource.getCode();
        if(code.equals("10086")){
            return Result.OK("平台管理库，不允许删除!");
        }
        DataSourceCachePool.removeCache(sysDataSource.getCode());
        removeById(id);
        return Result.OK("删除成功!");
    }

    /**
     * 动态添加公司 【注册mybatis动态公司】
     *
     * @param sysDataSource 添加公司数据对象
     * @param dbPassword    未加密的密码
     */
    private void addDynamicDataSource(SysDataSource sysDataSource, String dbPassword) {
        DataSourceProperty dataSourceProperty = new DataSourceProperty();
        dataSourceProperty.setUrl(sysDataSource.getDbUrl());
        dataSourceProperty.setPassword(dbPassword);
        dataSourceProperty.setDriverClassName(sysDataSource.getDbDriver());
        dataSourceProperty.setUsername(sysDataSource.getDbUsername());
        DynamicRoutingDataSource ds = (DynamicRoutingDataSource) dataSource;
        DataSource dataSource = dataSourceCreator.createDataSource(dataSourceProperty);
        try {
            ds.addDataSource(sysDataSource.getCode(), dataSource);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * 删除公司
     *
     * @param code
     */
    private void removeDynamicDataSource(String code) {
        DynamicRoutingDataSource ds = (DynamicRoutingDataSource) dataSource;
        ds.removeDataSource(code);
    }

    /**
     * 检查公司编号是否存在
     *
     * @param dbCode
     * @return
     */
    private long checkDbCode(String dbCode) {
        QueryWrapper<SysDataSource> qw = new QueryWrapper();
        qw.lambda().eq(true, SysDataSource::getCode, dbCode);
        return count(qw);
    }

}
