package com.example.mybatistraining1.test.config;

import com.example.mybatistraining1.test.utils.ReflectHelper;
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.executor.statement.StatementHandler;
import org.apache.ibatis.mapping.BoundSql;
import org.apache.ibatis.mapping.MappedStatement;
import org.apache.ibatis.mapping.ParameterMapping;
import org.apache.ibatis.mapping.ParameterMode;
import org.apache.ibatis.plugin.*;
import org.apache.ibatis.session.RowBounds;
import org.apache.ibatis.type.TypeHandlerRegistry;
import sun.plugin2.main.server.ResultHandler;

import java.util.ArrayList;
import java.util.List;
import java.util.Properties;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

@Intercepts({@Signature(type=StatementHandler.class,method="query",args={MappedStatement.class,Object.class, RowBounds.class, ResultHandler.class})})
@Slf4j
public class MybatisLogInterceptorPlugin implements Interceptor {

    @Override
    public Object intercept(Invocation invocation) throws Throwable {
        StatementHandler statementHandler = (StatementHandler)invocation.getTarget();
        StatementHandler delegate = (StatementHandler) ReflectHelper.getValueByFieldName(statementHandler, "delegate");
        //获取SQL
        BoundSql boundSql = delegate.getBoundSql();
        //获取参数
        Object parameterObject = boundSql.getParameterObject();
        List<Object> params = new ArrayList<Object>();
        TypeHandlerRegistry typeHandlerRegistry = (TypeHandlerRegistry) ReflectHelper.getValueByFieldName(delegate, "configuration");

        List<ParameterMapping> parameterMappingList = boundSql.getParameterMappings();
        if(parameterMappingList != null){
            for (ParameterMapping parameterMapping: parameterMappingList){
                if(parameterMapping.getMode() != ParameterMode.OUT){
                    Object value;
                    String propertyName = parameterMapping.getProperty();
                    if(boundSql.hasAdditionalParameter(propertyName)){
                        value = boundSql.getAdditionalParameter(propertyName);
                    } else if (parameterObject == null){
                        value = null;
                    } else if (typeHandlerRegistry.hasTypeHandler(parameterObject.getClass())){
                        value = parameterObject;
                    } else {
                        value = null;
                    }
                    params.add(value);
                }

                String sql = boundSql.getSql();
                for (Object param : params){
                    String paramStr;
                    Pattern pattern = Pattern.compile("^-?[0-9]+");
                    Matcher isNum = pattern.matcher(param+"");
                    if( !isNum.matches() ){
                        paramStr = "'"+param+"'";
                    } else {
                        paramStr = param+"";
                    }
                    sql = sql.replaceFirst("[?]", paramStr);
                }
                log.info("SQL："+sql);
            }
        }
        return invocation.proceed();
    }

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

    @Override
    public void setProperties(Properties properties) {

    }
}
