package com.yeejoin.amos.boot.biz.config;

import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.handlers.MetaObjectHandler;
import com.baomidou.mybatisplus.core.toolkit.Constants;
import com.yeejoin.amos.boot.biz.common.annotation.FillCommonUserField;
import com.yeejoin.amos.boot.biz.common.annotation.PipeLengthField;
import com.yeejoin.amos.boot.biz.common.annotation.RecUserNameFilling;
import com.yeejoin.amos.boot.biz.common.bo.ReginParams;
import com.yeejoin.amos.boot.biz.common.constants.BizConstant;
import com.yeejoin.amos.boot.biz.common.utils.RedisKey;
import com.yeejoin.amos.boot.biz.common.utils.RedisUtils;
import com.yeejoin.amos.feign.privilege.model.AgencyUserModel;
import lombok.RequiredArgsConstructor;
import org.apache.commons.lang3.StringUtils;
import org.apache.ibatis.reflection.MetaObject;
import org.springframework.stereotype.Component;
import org.typroject.tyboot.core.foundation.context.RequestContext;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.*;

/**
 * @author Dell
 */
@Component
@RequiredArgsConstructor
public class MetaHandler implements MetaObjectHandler {


    private final RedisUtils redisUtils;


    /**
     * 新增数据拦截
     *
     * @param metaObject 原始对象
     */
    @Override
    public void insertFill(MetaObject metaObject) {
        Date currentDate = new Date();
        Class<?> clazz = getaClass(metaObject);
        autoFillUser(clazz.getAnnotation(FillCommonUserField.class), metaObject, currentDate);
        autoFillPipeLength(clazz.getAnnotation(PipeLengthField.class), metaObject);
        fillRecUserName(clazz.getAnnotation(RecUserNameFilling.class), metaObject);
        this.setFieldValByName("createDate", currentDate, metaObject);
    }

    private void fillRecUserName(RecUserNameFilling annotation, MetaObject metaObject) {
        if (annotation != null) {
            recUserNameSave(metaObject);
        }
    }

    private void recUserNameSave(MetaObject metaObject) {
        String userName = this.getRealNameFromLoginInfo();
        if(StringUtils.isNotEmpty(userName)){
            this.setFieldValByName("recUserName", userName, metaObject);
        }
    }

    private String getRealNameFromLoginInfo() {
        Object redisUserData = redisUtils.get(RedisKey.buildReginKey(RequestContext.getExeUserId(), RequestContext.getToken()));
        ReginParams reginParams = JSONObject.parseObject(Optional.ofNullable(redisUserData).map(Object::toString).orElse(null), ReginParams.class);
        return Optional.ofNullable(reginParams).map(ReginParams::getUserModel).map(AgencyUserModel::getRealName).orElse("");
    }


    /**
     * 更新拦截
     *
     * @param metaObject 原始对象
     */
    @Override
    public void updateFill(MetaObject metaObject) {
        Date currentDate = new Date();
        Class<?> clazz = getaClass(metaObject);
        autoFillUser(clazz.getAnnotation(FillCommonUserField.class), metaObject, currentDate);
        autoFillPipeLength(clazz.getAnnotation(PipeLengthField.class), metaObject);
    }

    private void autoFillUser(FillCommonUserField clazz, MetaObject metaObject, Date currentDate) {
        if (clazz == null || clazz.isAutoFill()) {
            recInfoUpdate(metaObject, currentDate);
        }
    }

    private void autoFillPipeLength(PipeLengthField clazz, MetaObject metaObject) {
        if (clazz != null) {
            processAutoFill(metaObject, clazz);
        }
    }

    private void recInfoUpdate(MetaObject metaObject, Date currentDate) {
        this.setFieldValByName("recUserId", RequestContext.getExeUserId(), metaObject);
        this.setFieldValByName("recDate", currentDate, metaObject);
        this.setFieldValByName("updateTime", currentDate, metaObject);
    }

    private static Class<?> getaClass(MetaObject metaObject) {
        Object originalObj = metaObject.getOriginalObject();
        Class<?> clazz = originalObj.getClass();
        // 处理 Map 封装的情况（update(entity, wrapper) 方式）
        if (originalObj instanceof Map) {
            Map<?, ?> map = (Map<?, ?>) originalObj;
            Object et = map.get(Constants.ENTITY);  // MyBatis-Plus 的实体key
            clazz = (et != null) ? et.getClass() : clazz;
        }
        return clazz;
    }


    private void processAutoFill(MetaObject metaObject, PipeLengthField pipeLengthField) {
        // 1. 防御性校验
        if (metaObject == null || pipeLengthField == null) {
            return;
        }
        if (StringUtils.isBlank(pipeLengthField.sourceField()) ||
                StringUtils.isBlank(pipeLengthField.targetField())) {
            return;
        }

        // 2. 获取实际要操作的对象（处理Map封装情况）
        Object operationObj = getOperationObject(metaObject);
        if (operationObj == null) {
            return;
        }

        // 3. 重新基于实际对象创建MetaObject
        MetaObject targetMetaObject = metaObject.hasGetter(Constants.ENTITY)
                ? MetaObject.forObject(operationObj, metaObject.getObjectFactory(), metaObject.getObjectWrapperFactory(), metaObject.getReflectorFactory())
                : metaObject;

        // 4. 安全取值
        if (!targetMetaObject.hasGetter(pipeLengthField.sourceField())) {
            return;
        }

        Object sourceValue = targetMetaObject.getValue(pipeLengthField.sourceField());
        if (sourceValue == null) {
            return;
        }

        // 5. 转换并设值
        Object convertedValue = convertValue(sourceValue, pipeLengthField);
        this.setFieldValByName(pipeLengthField.targetField(), convertedValue, targetMetaObject);
    }

    /**
     * 处理Map类型的参数封装
     */
    private Object getOperationObject(MetaObject metaObject) {
        Object original = metaObject.getOriginalObject();

        // 处理update(entity, wrapper)产生的Map封装
        if (original instanceof Map) {
            Map<?, ?> map = (Map<?, ?>) original;
            // MyBatis-Plus的标准实体key
            return map.get(Constants.ENTITY) == null ? original : map.get(Constants.ENTITY);
        }
        return original;
    }


    private Object convertValue(Object sourceValue, PipeLengthField pipeLengthField) {
        // 示例：针对pipeLength的特殊处理
        if (BizConstant.PIPE_LENGTH.equals(pipeLengthField.sourceField())) {
            return Arrays.stream(sourceValue.toString().split("/")).filter(Objects::nonNull)
                    .map(BigDecimal::new).reduce(BigDecimal.ZERO, BigDecimal::add).setScale(3, RoundingMode.HALF_UP).stripTrailingZeros().toPlainString();
        }
        // 可扩展其他转换规则
        return sourceValue;
    }
}