package cn.fateverse.query.aspect;

import cn.fateverse.common.core.exception.CustomException;
import cn.fateverse.query.entity.DataSourceManage;
import cn.fateverse.query.factory.DynamicDataSourceService;
import cn.fateverse.query.mapper.DataSourceManageMapper;
import cn.fateverse.query.mapper.DynamicDataSourceMapper;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.springframework.stereotype.Component;

import java.lang.reflect.Field;

/**
 * @author Clay
 * @date 2023-07-16
 */
@Slf4j
@Aspect
@Component
public class DynamicDataSourceAspect {

    private final DataSourceManageMapper dataSourceManageMapper;

    private final DynamicDataSourceService dynamicDataSourceService;

    public DynamicDataSourceAspect(DataSourceManageMapper dataSourceManageMapper,
                                   DynamicDataSourceService dynamicDataSourceService) {
        this.dataSourceManageMapper = dataSourceManageMapper;
        this.dynamicDataSourceService = dynamicDataSourceService;
    }

    @SneakyThrows
    @Around("execution(* cn.fateverse.query.service.DynamicDataSourceTableService.*(..))")
    public Object around(ProceedingJoinPoint point) {
        try {
            Object[] args = point.getArgs();
            Long dataSourceId = (Long) args[args.length - 1];
            //获取到当前数据源id的数据源
            DataSourceManage dataSourceManage = dataSourceManageMapper.selectById(dataSourceId);
            if (null == dataSourceManage) {
                throw new CustomException("数据源错误!");
            }
            DynamicDataSourceMapper dataSourceServiceMapper = dynamicDataSourceService.getMapper(dataSourceManage);
            //获取到当前代理的对象
            Object target = point.getTarget();
            Class<?> targetClass = target.getClass();
            Field dataSourceManageField = targetClass.getDeclaredField("dataSourceManage");
            dataSourceManageField.setAccessible(true);
            dataSourceManageField.set(target, dataSourceManage);
            //根据数据源信息来获取到对应的具体mapper实现
            Field dynamicDataSourceMapperField = targetClass.getDeclaredField("dynamicDataSourceMapper");
            dynamicDataSourceMapperField.setAccessible(true);
            dynamicDataSourceMapperField.set(target, dataSourceServiceMapper);
            //运行代理的函数
            Object proceed;
            try {
                proceed = point.proceed();
            } catch (Exception e) {
                log.error("数据源{}连接失败", dataSourceManage.getDsName(), e);
                dynamicDataSourceService.remove(dataSourceId);
                throw e;
            }
            //将表格mapper对象置null
            dynamicDataSourceMapperField.set(target, null);
            //对数据源对象置null
            dataSourceManageField.set(target, null);
            //返回对象
            return proceed;
        } finally {
            //关闭session
            dynamicDataSourceService.closeSqlSession();
        }
    }
}
