package com.ruoyi.framework.aspectj.scop;

import com.ruoyi.common.utils.SecurityUtils;
import com.ruoyi.common.utils.StringUtils;
import com.ruoyi.framework.annotation.Dynamic;
import lombok.extern.slf4j.Slf4j;
import org.apache.ibatis.executor.statement.StatementHandler;
import org.apache.ibatis.mapping.BoundSql;
import org.apache.ibatis.plugin.Interceptor;
import org.apache.ibatis.plugin.Intercepts;
import org.apache.ibatis.plugin.Invocation;
import org.apache.ibatis.plugin.Signature;
import org.apache.ibatis.reflection.DefaultReflectorFactory;
import org.apache.ibatis.reflection.MetaObject;
import org.apache.ibatis.reflection.SystemMetaObject;
import org.springframework.stereotype.Component;

import java.sql.Connection;

/**
 * @author qing
 * @date 2024/4/21
 * @desc DynamicSqlInterceptor @Dynamic 注解的拦截器
 */

@Slf4j
@Component
@Intercepts({
        @Signature(type = StatementHandler.class, method = "prepare", args = {Connection.class, Integer.class})
})

// @Dynamic
public class DynamicSqlInterceptor implements Interceptor {

    // static final Dynamic DATA_PERMISSION_NULL ;


    String wrapperSql = " select Temp.*\n" +
            "from ({}) Temp\n" +
            "         inner join (SELECT p.premession_char\n" +
            "                     FROM (SELECT @premessionStr := '{}' p) param,\n" +
            "                          getpremessionview_chars p) permission\n" +
            "                    on permission.premession_char = Temp.{}; ";


    @Override
    @Dynamic
    public Object intercept(Invocation invocation) throws Throwable {
        // 1. 获取 StatementHandler 对象, 即执行 SQL
        StatementHandler statementHandler = (StatementHandler) invocation.getTarget();

        // 2. MetaObject 获取 StatementHandler 对象的元数据
        MetaObject metaObject = MetaObject.forObject(statementHandler,
                SystemMetaObject.DEFAULT_OBJECT_FACTORY,
                SystemMetaObject.DEFAULT_OBJECT_WRAPPER_FACTORY,
                new DefaultReflectorFactory());

        // // 3. 通过 metaObject 反射获取 StatementHandler 对象的属性值: mappedStatement
        // MappedStatement mappedStatement = (MappedStatement) metaObject.getValue("delegate.mappedStatement");
        // // mappedStatement 对象的 id 即为 mapper 接口的方法全路径名
        // String id = mappedStatement.getId();
        //
        // // 4. 通过 id 获取到 Dao 层类的全限定名, 然后反射获取 Class 对象
        // Class<?> clazz = Class.forName(id.substring(0, id.lastIndexOf(".")));

        // 5. 获取包含原始 sql 语句的 BoundSql 对象
        BoundSql boundSql = statementHandler.getBoundSql();
        String sql = boundSql.getSql();

        // 拦截方法
        String mSql = null;

        // // 6. 获取 Method 对象
        // Method method = clazz.getDeclaredMethod(id.substring(id.lastIndexOf(".") + 1));
        // 6. 遍历方法, 获取方法上的注解
        // for (Method method : clazz.getDeclaredMethods()) {
        //     // 7. 判断方法上是否有 @Dynamic 注解
        //     Dynamic dynamic = AnnotationUtils.findAnnotation(method, Dynamic.class);
        //     if (dynamic != null) {
        //         mSql = sql + SQL_SUFFIX;
        //         break;
        //     }
        // }

        Dynamic dynamic = DataPermissionContextHolder.get();
        if (dynamic != null) {
            log.debug("原始 sql 语句: {}", sql);

            mSql = StringUtils.format(
                    wrapperSql, sql, SecurityUtils.getPermissionCharIns(), dynamic.value());
            log.debug("拦截 sql 语句: {}", mSql);
        }


        if (mSql != null) {
            // 8. 通过反射设置新的 sql 语句
            metaObject.setValue("delegate.boundSql.sql", mSql);
        }

        // 9. 执行原逻辑
        return invocation.proceed();
    }
}