package org.jeecg.config.mybatis;

import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import lombok.extern.slf4j.Slf4j;
import org.apache.ibatis.binding.MapperMethod.ParamMap;
import org.apache.ibatis.executor.Executor;
import org.apache.ibatis.mapping.MappedStatement;
import org.apache.ibatis.mapping.SqlCommandType;
import org.apache.ibatis.plugin.*;
import org.jeecg.common.aspect.annotation.DictFillIn;
import org.jeecg.common.util.oConvertUtils;
import org.jeecg.modules.system.entity.SysDict;
import org.jeecg.modules.system.entity.SysDictItem;
import org.jeecg.modules.system.mapper.SysDictItemMapper;
import org.jeecg.modules.system.mapper.SysDictMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Component;

import java.lang.reflect.Field;
import java.util.Arrays;
import java.util.List;
import java.util.Properties;
import java.util.stream.Collectors;

/**
 * 记录编辑的时候修改了哪些字段
 *
 * @Author sunwd
 * @date 2024/4/24
 */
@Slf4j
@Component
@Intercepts({@Signature(type = Executor.class, method = "update", args = {MappedStatement.class, Object.class})})
public class DictFillInMybatisInterceptor implements Interceptor {

    @Lazy
    @Autowired
    private SysDictMapper sysDictMapper;
    @Lazy
    @Autowired
    private SysDictItemMapper sysDictItemMapper;

    @Override
    public Object intercept(Invocation invocation) throws Throwable {
        MappedStatement mappedStatement = (MappedStatement) invocation.getArgs()[0];
        String sqlId = mappedStatement.getId();
        SqlCommandType sqlCommandType = mappedStatement.getSqlCommandType();
        Object parameter = invocation.getArgs()[1];

        if (parameter == null) {
            return invocation.proceed();
        }

        if (SqlCommandType.UPDATE == sqlCommandType || SqlCommandType.INSERT == sqlCommandType) {
            Field[] fields = null;
            if (parameter instanceof ParamMap) {
                ParamMap<?> p = (ParamMap<?>) parameter;
                String et = "et";
                if (p.containsKey(et)) {
                    parameter = p.get(et);
                } else {
                    parameter = p.get("param1");
                }
                if (parameter == null) {
                    return invocation.proceed();
                }
                fields = oConvertUtils.getAllFields(parameter);
            } else {
                fields = oConvertUtils.getAllFields(parameter);
            }
            for (Field field : fields) {
                if (field.getAnnotation(DictFillIn.class) != null) {
                    String code = field.getAnnotation(DictFillIn.class).dicCode();
                    String refField = field.getAnnotation(DictFillIn.class).refField();
                    field.setAccessible(true);
                    Object dictValue = getDictValue(parameter, fields, code, refField);
                    log.debug("@DictFillIn进行字典值填充 | 字典编码为[{}] | 取值字段为[{}] | 填充字段为[{}] | 填充值为[{}]", code, refField, field.getName(), dictValue);
                    field.set(parameter, dictValue);
                    field.setAccessible(false);
                }
            }
        }
        return invocation.proceed();
    }

    private Object getDictValue(Object parameter, Field[] fields, String code, String refField) throws IllegalAccessException {
        for (Field field : fields) {
            if (field.getName().equals(refField)) {
                field.setAccessible(true);
                String value = String.valueOf(field.get(parameter));
                field.setAccessible(false);
                if (StrUtil.isBlank(value)) return null;

                SysDict sysDict = sysDictMapper.selectOne(Wrappers.lambdaQuery(SysDict.class).eq(SysDict::getDictCode, code).select(SysDict::getId));
                if (sysDict == null || StrUtil.isBlank(sysDict.getId())) return null;

                List<SysDictItem> list = sysDictItemMapper.selectList(Wrappers.lambdaQuery(SysDictItem.class)
                        .eq(SysDictItem::getDictId, sysDict.getId())
                        .in(SysDictItem::getItemValue, Arrays.asList(value.split(","))));
                return list.stream().map(SysDictItem::getItemText).collect(Collectors.joining(","));
            }
        }
        return null;
    }

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

    @Override
    public void setProperties(Properties properties) {
    }

}
