package com.persagy.dmp.mybatis.handler;

import com.persagy.dmp.common.context.AppContext;
import com.persagy.dmp.common.lang.PsDateTime;
import com.persagy.dmp.common.model.entity.AuditableEntity;
import lombok.extern.slf4j.Slf4j;
import org.apache.ibatis.executor.Executor;
import org.apache.ibatis.mapping.MappedStatement;
import org.apache.ibatis.mapping.SqlCommandType;
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.springframework.stereotype.Component;

import java.util.Collection;
import java.util.Map;

/**
 * 审计信息拦截器
 * 保存前审计信息赋值公共处理
 * @author Charlie Yu
 * @date 2021-06-16
 */
@Slf4j
@Component
@Intercepts({@Signature(type = Executor.class, method = "update", args = {MappedStatement.class, Object.class})})
public class AuditInfoHandler implements Interceptor {

    @Override
    public Object intercept(Invocation invocation) throws Throwable {
        MappedStatement mappedStatement = (MappedStatement) invocation.getArgs()[0];
        SqlCommandType sqlCommandType = mappedStatement.getSqlCommandType();
        // 新增/修改时才需要处理
        if(SqlCommandType.INSERT != sqlCommandType && SqlCommandType.UPDATE != sqlCommandType) {
            return invocation.proceed();
        }
        doSetting(invocation.getArgs()[1], SqlCommandType.INSERT == sqlCommandType);
        return invocation.proceed();
    }

    /**
     * 递归查找对象，并修改审计信息
     * @param parameter
     */
    private void doSetting(Object parameter, boolean isInsert) {
        if(parameter == null) {
            return;
        }
        // 如果是Map，则取所有value递归
        if(parameter instanceof Map) {
            ((Map) parameter).values().forEach(p -> doSetting(p, isInsert));
        } else if(parameter instanceof Collection) {
            // 如果是集合,则按对象递归
            ((Collection) parameter).forEach(p -> doSetting(p, isInsert));
        } else {
            // 如果是对象，则执行审计信息修改
            setAuditInfo(parameter, isInsert);
        }
    }

    /**
     * 修改审计信息
     * @param parameter
     * @param isInsert 是否为新增
     */
    private void setAuditInfo(Object parameter, boolean isInsert) {
        // 只处理AuditableEntity
        if(!(parameter instanceof AuditableEntity)) {
            return;
        }
        AuditableEntity entity = (AuditableEntity) parameter;
        // 新增 - 创建人、创建时间赋值
        if (isInsert) {
            entity.setCreator(AppContext.getContext().getAccountId());
            entity.setCreationTime(new PsDateTime());
        } else {
            // 修改 - 修改人、修改时间更新
            entity.setModifier(AppContext.getContext().getAccountId());
            entity.setModifiedTime(new PsDateTime());
        }
    }
}
