package com.example.cuixiaowei.demo;

import com.alibaba.fastjson.JSONObject;
import org.apache.ibatis.executor.statement.StatementHandler;
import org.apache.ibatis.logging.Log;
import org.apache.ibatis.logging.LogFactory;
import org.apache.ibatis.mapping.BoundSql;
import org.apache.ibatis.mapping.ParameterMapping;
import org.apache.ibatis.plugin.*;
import org.apache.ibatis.session.ResultHandler;

import java.sql.Statement;
import java.util.List;
import java.util.Map;
import java.util.Properties;

/**
 * <p>
 *
 * </p>
 *
 * @author wei.liu
 * @date 2020/1/2
 */
@Intercepts({
        @Signature(type = StatementHandler.class, method = "query", args = {Statement.class, ResultHandler.class}),
        @Signature(type = StatementHandler.class, method = "update", args = {Statement.class}),
        @Signature(type = StatementHandler.class, method = "batch", args = { Statement.class })
})
public class MyInterceptor implements Interceptor {
    final Log log = LogFactory.getLog(MyTypeHandle.class);

    @Override
    public Object intercept(Invocation invocation) throws Throwable {
        Object target = invocation.getTarget();

        long startTime = System.currentTimeMillis();

        StatementHandler statementHandler = (StatementHandler)target;

        try {
            return invocation.proceed();
        } finally {
            long endTime = System.currentTimeMillis();
            long sqlCost = endTime - startTime;

            BoundSql boundSql = statementHandler.getBoundSql();
            String sql = boundSql.getSql();
            Object parameterObject = boundSql.getParameterObject();
            List<ParameterMapping> parameterMappingList = boundSql.getParameterMappings();

            // 格式化Sql语句，去除换行符，替换参数
            sql = formatSql(sql, parameterObject, parameterMappingList);

            log.warn("执行耗时[" + sqlCost + "ms] " + "SQL：" + sql + ";");

        }
    }

    private String formatSql(String sql, Object parameterObject, List<ParameterMapping> parameterMappingList) {
        sql = sql.replaceAll("\r|\n|\t", " ").replaceAll("\\s+", " ");
        if(parameterObject == null){
            sql = sql.replaceAll("\\?", " null");
            return sql;
        }

        if(Map.class.isAssignableFrom(parameterObject.getClass())){
            Map pb = (Map)parameterObject;
            for(ParameterMapping temp: parameterMappingList){
                if (pb.get(temp.getProperty()) != null){
                    if (pb.get(temp.getProperty()).getClass().isAssignableFrom(JSONObject.class)){
                        JSONObject infObject = (JSONObject) pb.get(temp.getProperty());
                        sql = sql.replaceFirst("\\?","'" + infObject.toJSONString() + "'");
                    }else {
                        sql = sql.replaceFirst("\\?","'" + pb.get(temp.getProperty()) + "'");
                    }
                }else {
                    sql = sql.replaceFirst("\\?","'null'");
                }
            }
        }

        if(String.class.isAssignableFrom(parameterObject.getClass())) {
            sql = sql.replaceFirst("\\?", parameterObject == null ? "null" : "'" + parameterObject + "'");
        }

        if(Number.class.isAssignableFrom(parameterObject.getClass())) {
            sql = sql.replaceFirst("\\?", parameterObject == null ? "null" : parameterObject.toString());
        }

        return sql;
    }

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

    @Override
    public void setProperties(Properties properties) {

    }
}
