//package org.jeecg.config.saas;
//
//import com.baomidou.dynamic.datasource.DynamicRoutingDataSource;
//import com.baomidou.dynamic.datasource.creator.DataSourceProperty;
//import com.baomidou.dynamic.datasource.creator.DefaultDataSourceCreator;
//import com.baomidou.dynamic.datasource.toolkit.DynamicDataSourceContextHolder;
//import org.aspectj.lang.annotation.Aspect;
//import org.jeecg.modules.system.util.SecurityUtil;
//import org.slf4j.Logger;
//import org.slf4j.LoggerFactory;
//import org.springframework.jdbc.core.JdbcTemplate;
//import org.springframework.stereotype.Component;
//import javax.annotation.Resource;
//import javax.sql.DataSource;
//import java.util.Map;
//import java.util.Set;
//import java.util.concurrent.ConcurrentHashMap;
//import org.aspectj.lang.annotation.Pointcut;
//import org.aspectj.lang.annotation.Before;
//import org.aspectj.lang.JoinPoint;
//import javax.servlet.http.HttpServletRequest;
//import org.springframework.web.context.request.RequestAttributes;
//import org.springframework.web.context.request.RequestContextHolder;
//import org.springframework.web.context.request.ServletRequestAttributes;
//
//@Aspect
//@Component
//public class TenantDataSourceAop {
//
//    private static final Logger log = LoggerFactory.getLogger(TenantDataSourceAop.class);
//
//    @Resource
//    private DataSource dataSource; // 动态数据源代理
//
//    @Resource(name = "dataSource")
//    private DataSource masterDataSource; // 主库物理数据源
//
//    @Resource
//    private DefaultDataSourceCreator dataSourceCreator; // 必须加这个
//
//    // 已注册的数据源缓存
//    private final Set<String> dsCache = ConcurrentHashMap.newKeySet();
//
//    // 记录数据源注册失败的租户及失败时间戳
//    private final ConcurrentHashMap<String, Long> errorDsCache = new ConcurrentHashMap<>();
//
//    // 自动恢复间隔，单位毫秒（如1分钟）
//    private static final long AUTO_RECOVER_INTERVAL = 60 * 1000;
//
//    @Pointcut("within(@org.springframework.web.bind.annotation.RestController *) || within(@org.springframework.stereotype.Controller *)")
//    public void controllerPointcut() {}
//
//    @Before("controllerPointcut()")
//    public void before(JoinPoint joinPoint) {
//        // 获取当前请求上下文
//        RequestAttributes requestAttributes = RequestContextHolder.getRequestAttributes();
//        if (requestAttributes == null) return;
//        HttpServletRequest request = ((ServletRequestAttributes) requestAttributes).getRequest();
//        String tenantCode = request.getHeader("X-Tenant-Code");
//
//        // 特殊情况：主库、未指定、多租户白名单，直接切回主数据源
//        if (tenantCode == null || tenantCode.trim().isEmpty()
//                || "undefined".equalsIgnoreCase(tenantCode.trim())
//                || "null".equalsIgnoreCase(tenantCode.trim())
//                || "master".equalsIgnoreCase(tenantCode.trim())
//                || "10086".equals(tenantCode.trim())) {
//            DynamicDataSourceContextHolder.push("master");
//            log.warn("[多租户数据源] 当前请求未指定租户（X-Tenant-Code），使用主数据源 master");
//            return;
//        }
//
//        // 检查租户是否在错误缓存中，未超时则拒绝
//        Long lastFailTime = errorDsCache.get(tenantCode);
//        if (lastFailTime != null) {
//            long now = System.currentTimeMillis();
//            if (now - lastFailTime < AUTO_RECOVER_INTERVAL) {
//                log.warn("[多租户数据源] 租户【{}】数据源注册曾失败，未到自动恢复时间，禁止切换！", tenantCode);
//                throw new RuntimeException("租户【" + tenantCode + "】数据源注册曾失败，请1分钟后重试或检查配置！");
//            } else {
//                errorDsCache.remove(tenantCode); // 到期自动恢复
//                log.warn("[多租户数据源] 租户【{}】自动移出失败黑名单，允许重新注册。", tenantCode);
//            }
//        }
//
//        DynamicRoutingDataSource dynamicRoutingDataSource = (DynamicRoutingDataSource) dataSource;
//        Set<String> allDs = dynamicRoutingDataSource.getDataSources().keySet();
//        // 已经存在的数据源直接切换
//        if (allDs.contains(tenantCode) || dsCache.contains(tenantCode)) {
//            DynamicDataSourceContextHolder.push(tenantCode);
//            log.warn("[多租户数据源] 切换到已存在的租户数据源：{}", tenantCode);
//            return;
//        }
//
//        // 走到这里说明要动态注册新数据源
//        JdbcTemplate jdbc = new JdbcTemplate(masterDataSource);
//        Map<String, Object> row;
//        try {
//            // 查询数据源配置表
//            row = jdbc.queryForMap(
//                    "SELECT code, db_url, db_name, db_username, db_password, db_driver FROM sys_data_source WHERE code=?",
//                    tenantCode
//            );
//        } catch (Exception e) {
//            errorDsCache.put(tenantCode, System.currentTimeMillis()); // 查不到也记录失败时间
//            log.warn("[多租户数据源] 租户【{}】查询主库失败或不存在，自动加入失败黑名单：{}", tenantCode, e.getMessage());
//            throw new RuntimeException("租户【" + tenantCode + "】不存在，或查询主库失败！");
//        }
//
//        // 拼接数据库URL（带参数，避免重复斜杠）
//        String dbUrl = String.valueOf(row.get("db_url"));
//        String dbName = String.valueOf(row.get("db_name"));
//        String url;
//        if (dbUrl.contains("?")) {
//            url = dbUrl.replaceAll("/+$", "");
//        } else {
//            url = dbUrl.replaceAll("/+$", "") + "/" + dbName + "?characterEncoding=UTF-8&useSSL=false&serverTimezone=Asia/Shanghai";
//        }
//
//        DataSourceProperty dsp = new DataSourceProperty();
//        dsp.setUrl(url);
//        dsp.setUsername(String.valueOf(row.get("db_username")));
//
//        // 数据库中的密码是加密的，需要解密
//        String db_password = String.valueOf(row.get("db_password"));
//        String pwd = SecurityUtil.jiemi(db_password);
//        dsp.setPassword(pwd);
//        dsp.setDriverClassName(String.valueOf(row.get("db_driver")));
//
//        log.warn("[多租户数据源] 租户【{}】准备动态注册数据源，URL={}，用户名={}", tenantCode, url, dsp.getUsername());
//
//        try {
//            javax.sql.DataSource realDs = dataSourceCreator.createDataSource(dsp);
//            dynamicRoutingDataSource.addDataSource(tenantCode, realDs);
//            dsCache.add(tenantCode);
//            errorDsCache.remove(tenantCode); // 注册成功，移除黑名单
//            log.warn("[多租户数据源] 租户【{}】数据源注册成功，已切换。", tenantCode);
//        } catch (Exception ex) {
//            errorDsCache.put(tenantCode, System.currentTimeMillis());
//            log.warn("[多租户数据源] 租户【{}】数据源注册失败，错误：{}", tenantCode, ex.getMessage());
//            throw new RuntimeException("租户【" + tenantCode + "】数据源注册失败！" + ex.getMessage());
//        }
//        DynamicDataSourceContextHolder.push(tenantCode);
//    }
//}
