package cn.reghao.oss.store.config.mysql;

import cn.reghao.jutil.jdk.db.Page;
import org.apache.ibatis.binding.MapperMethod;
import org.apache.ibatis.executor.parameter.ParameterHandler;
import org.apache.ibatis.executor.statement.StatementHandler;
import org.apache.ibatis.mapping.MappedStatement;
import org.apache.ibatis.plugin.*;
import org.apache.ibatis.reflection.MetaObject;
import org.apache.ibatis.reflection.SystemMetaObject;

import java.sql.Connection;
import java.util.Properties;

/**
 * MyBatis 分页拦截器
 *
 * @author reghao
 * @date 2021-04-26 17:40:32
 */
@Intercepts({@Signature(type=StatementHandler.class,method="prepare",args={Connection.class,Integer.class})})
public class PageListInterceptor implements Interceptor {
    private final String methodSuffix = "ByPage";
    @Deprecated
    private int page;
    @Deprecated
    private int size;
    private String dbType;

    @Override
    public Object intercept(Invocation invocation) throws Throwable {
        StatementHandler statementHandler = (StatementHandler)invocation.getTarget();
        MetaObject metaObject = SystemMetaObject.forObject(statementHandler);
        while(metaObject.hasGetter("h")){
            Object object = metaObject.getValue("h");
            metaObject = SystemMetaObject.forObject(object);
        }

        while(metaObject.hasGetter("target")){
            Object object = metaObject.getValue("target");
            metaObject = SystemMetaObject.forObject(object);
        }

        MappedStatement mappedStatement = (MappedStatement)metaObject.getValue("delegate.mappedStatement");
        String mapId = mappedStatement.getId();
        if (mapId.matches(String.format(".+%s$", methodSuffix))){
            ParameterHandler parameterHandler = (ParameterHandler)metaObject.getValue("delegate.parameterHandler");
            Object object = parameterHandler.getParameterObject();
            Page page;
            if (object instanceof Page) {
                page = (Page) object;
            } else if (object instanceof MapperMethod.ParamMap) {
                MapperMethod.ParamMap paramMap = (MapperMethod.ParamMap) object;
                Object param1 = paramMap.get("param1");
                if (param1 instanceof Page) {
                    page = (Page) param1;
                } else {
                    throw new Exception("byPage 方法的第一个参数不是 Page 类型");
                }
            } else {
                throw new Exception("没有 Page 类型的参数");
            }

            String sql = (String) metaObject.getValue("delegate.boundSql.sql");
            //sql += " limit "+(page-1)*size +","+size;
            sql += String.format(" limit %s,%s", (page.getPage()-1)*page.getSize(), page.getSize());
            metaObject.setValue("delegate.boundSql.sql", sql);
        }
        return invocation.proceed();
    }

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

    @Override
    public void setProperties(Properties properties) {
        String limit = properties.getProperty("limit","10");
        this.page = Integer.parseInt(limit);
        this.dbType = properties.getProperty("dbType", "mysql");
    }
}
