package com.Config;

import lombok.extern.slf4j.Slf4j;
import org.apache.ibatis.binding.MapperMethod;
import org.apache.ibatis.cache.CacheKey;
import org.apache.ibatis.executor.Executor;
import org.apache.ibatis.mapping.BoundSql;
import org.apache.ibatis.mapping.MappedStatement;
import org.apache.ibatis.mapping.ParameterMapping;
import org.apache.ibatis.plugin.*;
import org.apache.ibatis.session.ResultHandler;
import org.apache.ibatis.session.RowBounds;

import java.util.HashMap;
import java.util.List;
import java.util.Properties;

@Slf4j
@Intercepts(
        {
                @Signature(type = Executor.class, method = "query", args = {MappedStatement.class, Object.class, RowBounds.class, ResultHandler.class, CacheKey.class, BoundSql.class}),
                @Signature(type = Executor.class, method = "query", args = {MappedStatement.class, Object.class, RowBounds.class, ResultHandler.class}),
                @Signature(type = Executor.class, method = "update", args = {MappedStatement.class, Object.class})
//                @Signature(type = StatementHandler.class, method = "query", args = {MappedStatement.class, Object.class, RowBounds.class, ResultHandler.class}),

        }
)
public class CustomPlugin implements Interceptor {

    @Override
    public Object intercept(Invocation invocation) throws Throwable {
        Object[] args = invocation.getArgs();
        MappedStatement ms = (MappedStatement) args[0];
        Object parameter = args[1];
        Executor executor = (Executor) invocation.getTarget();
        CacheKey cacheKey = null;
        BoundSql boundSql = null;
        Class<?> type = ms.getParameterMap().getType();

        if (args.length >= 4) {
            boundSql = ms.getBoundSql(parameter);
            ResultHandler resultHandler = (ResultHandler) args[3];
            RowBounds rowBounds = (RowBounds) args[2];
            cacheKey = executor.createCacheKey(ms, parameter, rowBounds, boundSql);
            if (args.length == 6) {
                cacheKey = (CacheKey) args[4];
                boundSql = (BoundSql) args[5];
            }
            String sql = getSql(boundSql, type);
            log.debug("runing query(dql) sql:{}", sql);
            return executor.query(ms, parameter, rowBounds, resultHandler, cacheKey, boundSql);
        } else if (args.length == 2) {
            // update
            boundSql = ms.getBoundSql(parameter);
            String sql = getSql(boundSql, type);
            log.debug("runing update(dml) sql:{}", sql);
            return executor.update(ms, parameter);
        } else {
            throw new RuntimeException("无效拦截");
        }

    }

    /***
     * @author houchunjian
     * @date 2020/1/1 0001 15:04
     * @param boundSql
     * @param type
     * @return java.lang.String
     */
    private String getSql(BoundSql boundSql, Class<?> type) {
        String sql = boundSql.getSql();
        final String[] temp = {sql};
        if (sql.contains("?") && boundSql.getParameterMappings().size() > 0 && boundSql.getParameterObject() != null) {
            List<ParameterMapping> parameterMappings = boundSql.getParameterMappings();
            Object parameterObject = boundSql.getParameterObject();
            //多参数
            if (parameterObject instanceof HashMap) {
                MapperMethod.ParamMap parameterObject1 = (MapperMethod.ParamMap) parameterObject;
                parameterMappings.forEach(parameters -> {
                    String property = parameters.getProperty();
                    // todo 拦截过滤，大小过滤
                    String strs = String.valueOf(parameterObject1.get(property));
                    if (strs != null) {
                        temp[0] = temp[0].replaceFirst("\\?", "'" + strs + "'");
                    }
                });
            } else if (parameterObject instanceof String) {
                // 单参数
                parameterMappings.forEach(parameters -> {
                    // todo 拦截过滤，大小过滤
                    String strs = String.valueOf(parameterObject);
                    temp[0] = temp[0].replaceFirst("\\?", "'" + strs + "'");

                });
            } else if (parameterObject.getClass().isAssignableFrom(type)) {
                // 对象类型
                String ss = parameterObject.toString();
                String substring = ss;
                String[] strings = new String[1];
                strings[0]=ss;
                substring = substring.replaceFirst("\\(", "");
                substring = substring.replaceFirst("\\)", "");
                if (substring.contains("(") || substring.contains(")")) {
                    // 不管, 显示全部j对象数据
                } else {
                    substring =  strings[0];
                    substring = substring.replaceAll(" ", "");
                    HashMap<String, String> map = new HashMap<>();
                    int i = substring.indexOf("(");
                    int i1 = substring.lastIndexOf(")");
                    if (i != -1 && i1 != -1) {
                        substring = substring.substring(i + 1, i1);
                    }
                    // 若不存在复合类型的精准提供
                    String[] split = substring.split(",");
                    if (split.length > 0) {
                        for (String s : split) {
                            int i2 = s.indexOf("=");
                            String key = s.substring(0, i2);
                            String value = s.substring(i2 + 1);
                            map.put(key, value);
                        }
                    }
                    parameterMappings.forEach(parameters -> {
                        String property = parameters.getProperty();
                        String strs = String.valueOf(map.get(property));
                        temp[0] = temp[0].replaceFirst("\\?", "'" + strs + "'");

                    });

                }


            }

        }
        //TODO 自己要进行的各种处理
        return temp[0];
    }

    @Override
    public Object plugin(Object target) {
        return Plugin.wrap(target, this);
    }

    @Override
    public void setProperties(Properties properties) {
        //
    }

}
