package com.cf.imes.module.system.service.systemconfig.factory.service.impl;

import cn.hutool.core.util.NumberUtil;
import cn.hutool.core.util.ObjectUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.cf.imes.framework.common.enums.CommonStatusEnum;
import com.cf.imes.framework.common.exception.ErrorCode;
import com.cf.imes.framework.common.exception.ServiceException;
import com.cf.imes.framework.common.util.object.BeanUtils;
import com.cf.imes.framework.mybatis.core.query.LambdaQueryWrapperX;
import com.cf.imes.framework.organ.core.context.OrganContextHolder;
import com.cf.imes.module.system.controller.admin.systemconfig.vo.*;
import com.cf.imes.module.system.dal.dataobject.customplateno.CustomPlateNoSeqDO;
import com.cf.imes.module.system.dal.dataobject.systemconfig.SystemConfigDO;
import com.cf.imes.module.system.dal.dataobject.dict.DictDataDO;
import com.cf.imes.module.system.dal.mysql.customplateno.CustomPlateNoSeqMapper;
import com.cf.imes.module.system.dal.mysql.systemconfig.SystemConfigMapper;
import com.cf.imes.module.system.dal.redis.RedisKeyConstants;
import com.cf.imes.module.system.enums.customplateno.CustomPlateNoRuleCodeEnum;
import com.cf.imes.module.system.enums.config.SystemConfigTypeEnum;
import com.cf.imes.module.system.enums.customplateno.ResetModeEnum;
import com.cf.imes.module.system.service.systemconfig.factory.service.AbstractSystemConfigServiceHandler;
import com.cf.imes.module.system.service.customplateno.CustomPlateNoSeqService;
import com.cf.imes.module.system.service.dict.DictDataService;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;

import jakarta.annotation.Resource;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Optional;


import static com.cf.imes.module.system.enums.ErrorCodeConstants.*;

/**
 * 自定义板编号服务处理器
 *
 * @author Gqr
 * @since 2024/11/8 16:48
 */
@Service("customPlateNoServiceHandler")
@Slf4j
public class CustomPlateNoServiceHandler extends AbstractSystemConfigServiceHandler {
    @Resource
    private DictDataService dictDataService;

    @Resource
    private SystemConfigMapper systemConfigMapper;

    @Resource
    private StringRedisTemplate stringRedisTemplate;

    @Resource
    private CustomPlateNoSeqService customPlateNoSeqService;

    @Resource
    private CustomPlateNoSeqMapper customPlateNoSeqMapper;

    @Override
    public List<SystemConfigDO> selectList(ConfigPageReqVO pageReqVO) {
        SystemConfigTypeEnum customPlateNoEnum = SystemConfigTypeEnum.CUSTOM_PLATE_NO;
        List<SystemConfigDO> systemConfigDOS = systemConfigMapper.selectList(new LambdaQueryWrapperX<SystemConfigDO>()
                .eq(SystemConfigDO::getType, customPlateNoEnum.getType())
                .eq(SystemConfigDO::getOrganId, OrganContextHolder.getOrganId())
                .orderByAsc(SystemConfigDO::getVersion));
        if (systemConfigDOS.isEmpty()) {
            SystemConfigDO initCustomPlateNoConfig = new SystemConfigDO().builder().id(null).name(customPlateNoEnum.getName()).type(customPlateNoEnum.getType()).build();
            return List.of(initCustomPlateNoConfig);
        }
        // configDOPageResult下的自定义板编号配置只保留version最大的一项
        return systemConfigDOS.stream()
                .max(Comparator.comparing(SystemConfigDO::getVersion))
                .map(Collections::singletonList)
                .orElse(Collections.emptyList());
    }

    @Override
    public void checkValid(String setting) {
        // 字典中的时间格式
        List<DictDataDO> dateTypeFormatDictList = dictDataService.getDictDataList(CommonStatusEnum.ENABLE.getStatus(), "system_setting_date_type");
        try {
            JSONArray jsonArray = JSON.parseArray(setting);
            for (int i = 0; i < jsonArray.size(); i++) {
                JSONObject jsonObject = jsonArray.getJSONObject(i);
                String ruleCode = jsonObject.getString("ruleCode");
                // 1.校验code
                CustomPlateNoRuleCodeEnum custBoardRuleCodeEnum = checkRoleCode(ruleCode);

                // 2.自定义格式校验
                checkCustom(custBoardRuleCodeEnum, jsonObject);

                // 3.时间格式校验
                checkDateFormat(custBoardRuleCodeEnum, jsonObject.getString("dateValue"), dateTypeFormatDictList);

                // 4.序号类型校验数字和布尔类型
                checkNoType(custBoardRuleCodeEnum, jsonObject);

                // 5.复位类型校验
                checkResetMode(custBoardRuleCodeEnum, jsonObject.getInteger("resetMode"), ruleCode);
            }
        } catch (ServiceException e) {
            throw e;
        } catch (Exception e) {
            ErrorCode systemConfigCustomPlateNoRuleSaveCheckError = SYSTEM_CONFIG_CUSTOM_PLATE_NO_RULE_SAVE_CHECK_ERROR;
            log.error(systemConfigCustomPlateNoRuleSaveCheckError.getMsg(), e);
            throw new ServiceException(systemConfigCustomPlateNoRuleSaveCheckError);
        }
    }

    /**
     * 校验ruleCode
     *
     * @param ruleCode 规则编码
     */
    private CustomPlateNoRuleCodeEnum checkRoleCode(String ruleCode) {
        if (StringUtils.isEmpty(ruleCode)) {
            throw new ServiceException(CUSTOM_PLATE_NO_RULE_CHECK_RULECODE_EMPTY_ERROR);
        }
        CustomPlateNoRuleCodeEnum custBoardRuleCodeEnum = CustomPlateNoRuleCodeEnum.match(ruleCode);
        if (ObjectUtil.isNull(custBoardRuleCodeEnum)) {
            throw new ServiceException(CUSTOM_PLATE_NO_RULE_CHECK_RULECODE_NOT_MATCH_ERROR, ruleCode);
        }
        return custBoardRuleCodeEnum;
    }

    /**
     * 校验时间格式
     *
     * @param custBoardRuleCodeEnum 规则编码枚举
     * @param format                格式
     */
    private void checkDateFormat(CustomPlateNoRuleCodeEnum custBoardRuleCodeEnum, String format, List<DictDataDO> dateTypeFormatDictList) {
        if (ObjectUtil.equal(CustomPlateNoRuleCodeEnum.DATE, custBoardRuleCodeEnum) && StringUtils.isNotEmpty(format)) {
            Optional<DictDataDO> dateFormatDictDataOptional = dateTypeFormatDictList.stream().filter(d -> format.equals(d.getValue())).findAny();
            if (dateFormatDictDataOptional.isEmpty()) {
                throw new ServiceException(CUSTOM_PLATE_NO_RULE_CHECK_DATE_TYPE_FORMAT_ERROR, format);
            }
        }
    }

    /**
     * 校验自定义格式
     *
     * @param custBoardRuleCodeEnum
     * @param jsonObject
     */
    private void checkCustom(CustomPlateNoRuleCodeEnum custBoardRuleCodeEnum, JSONObject jsonObject) {
        if (ObjectUtil.equal(CustomPlateNoRuleCodeEnum.CUSTOM, custBoardRuleCodeEnum)) {
            if (ObjectUtil.isEmpty(jsonObject.get("strValue"))) {
                throw new ServiceException(CUSTOM_PLATE_NO_RULE_CHECK_CUSTOM_VALUE_EMPTY_ERROR, jsonObject.get("ruleCode"));
            }
        }
    }

    /**
     * 校验序号类型中数值和布尔类型的属性
     *
     * @param custBoardRuleCodeEnum
     * @param object
     */
    private void checkNoType(CustomPlateNoRuleCodeEnum custBoardRuleCodeEnum, JSONObject object) {
        // 序号类型才校验
        if (ObjectUtil.equal(CustomPlateNoRuleCodeEnum.ORDERNO, custBoardRuleCodeEnum)
                || ObjectUtil.equal(CustomPlateNoRuleCodeEnum.PLATENO, custBoardRuleCodeEnum)
                || ObjectUtil.equal(CustomPlateNoRuleCodeEnum.ROOMNO, custBoardRuleCodeEnum)
                || ObjectUtil.equal(CustomPlateNoRuleCodeEnum.BODYNO, custBoardRuleCodeEnum)
        ) {
            Map<String, String> intTypeFieldMap = new HashMap<>() {{
                put("initValue", "起始值");
                put("length", "位数");
                put("resetMode", "复位/清零模式");
                put("increment_step", "递增值");
            }};
            Map<String, String> bolTypeFieldMap = new HashMap<>() {{
                put("left_fill_zero", "是否左补零");
            }};
            String ruleName = object.getString("ruleName");
            intTypeFieldMap.forEach((k, v) -> checkInt(object.get(k), v, ruleName));
            bolTypeFieldMap.forEach((k, v) -> checkBol(object.get(k), v, ruleName));
        }
    }

    /**
     * 校验整型
     *
     * @param intObj
     * @param fieldName
     */
    private void checkInt(Object intObj, String fieldName, String ruleName) {
        if (ObjectUtil.isEmpty(intObj)) {
            throw new ServiceException(CUSTOM_PLATE_NO_RULE_CHECK_INT_TYPE_NO_EMPTY, ruleName, fieldName);
        }
        if (!NumberUtil.isInteger(intObj.toString())) {
            throw new ServiceException(CUSTOM_PLATE_NO_RULE_CHECK_INT_TYPE_ERROR, ruleName, fieldName, intObj);
        }
    }

    /**
     * 校验布尔型
     *
     * @param bolObj
     * @param fieldName
     */
    private void checkBol(Object bolObj, String fieldName, String ruleName) {
        if (ObjectUtil.isEmpty(bolObj)) {
            throw new ServiceException(CUSTOM_PLATE_NO_RULE_CHECK_INT_TYPE_NO_EMPTY, ruleName, fieldName);
        }
        if (!(bolObj instanceof Boolean)) {
            throw new ServiceException(CUSTOM_PLATE_NO_RULE_CHECK_BOL_TYPE_ERROR, ruleName, fieldName, bolObj);
        }
    }

    /**
     * 校验复位类型
     *
     * @param resetMode
     */
    private void checkResetMode(CustomPlateNoRuleCodeEnum custBoardRuleCodeEnum, Integer resetMode, String ruleCode) {
        boolean checkSuccess = true;
        if (ObjectUtil.equal(CustomPlateNoRuleCodeEnum.ORDERNO, custBoardRuleCodeEnum)) {
            checkSuccess = ObjectUtil.equal(resetMode, ResetModeEnum.DIGIT.getMode()) || ObjectUtil.equal(resetMode, ResetModeEnum.YEAR.getMode())
                    || ObjectUtil.equal(resetMode, ResetModeEnum.MONTH.getMode()) || ObjectUtil.equal(resetMode, ResetModeEnum.DAY.getMode());
        } else if (ObjectUtil.equal(CustomPlateNoRuleCodeEnum.PLATENO, custBoardRuleCodeEnum)) {
            checkSuccess = ObjectUtil.equal(resetMode, ResetModeEnum.ORDER.getMode()) || ObjectUtil.equal(resetMode, ResetModeEnum.YEAR.getMode())
                    || ObjectUtil.equal(resetMode, ResetModeEnum.MONTH.getMode()) || ObjectUtil.equal(resetMode, ResetModeEnum.DAY.getMode())
                    || ObjectUtil.equal(resetMode, ResetModeEnum.BODY.getMode()) || ObjectUtil.equal(resetMode, ResetModeEnum.ROOM.getMode());
        } else if (ObjectUtil.equal(CustomPlateNoRuleCodeEnum.ROOMNO, custBoardRuleCodeEnum)) {
            checkSuccess = ObjectUtil.equal(resetMode, ResetModeEnum.ORDER.getMode());
        } else if (ObjectUtil.equal(CustomPlateNoRuleCodeEnum.BODYNO, custBoardRuleCodeEnum)) {
            checkSuccess = ObjectUtil.equal(resetMode, ResetModeEnum.ORDER.getMode()) || ObjectUtil.equal(resetMode, ResetModeEnum.ROOM.getMode());
        }
        if (!checkSuccess) {
            throw new ServiceException(CUSTOM_PLATE_NO_RULE_CHECK_RESETMODE_ERROR, ruleCode, resetMode);
        }
    }


    @Override
    public void beforeSaveConfig(ConfigSaveReqVO reqVO) {
        // 查询机构下的现有自定义板编号配置最大版本号
        Integer maxCustomPlateNoSystemConfigVersion = systemConfigMapper.selectOrgMaxCustomPlateNoSystemConfigVersion(OrganContextHolder.getOrganId());
        // 版本号 + 1
        reqVO.setVersion((ObjectUtil.isNotNull(maxCustomPlateNoSystemConfigVersion) ? maxCustomPlateNoSystemConfigVersion : 0) + 1);
        // 自定义板编号每次保存都创建新版本
        reqVO.setId(null);
    }

    @Override
    public void afterSaveConfig(SystemConfigDO systemConfigDO, ConfigSaveReqVO reqVO) {
        int currentVersion = systemConfigDO.getVersion();
        // 保留的最小版本号，小于他的都要删除
        int minReserveVersion = 0;
        if (currentVersion > 10) {
            minReserveVersion = currentVersion - 10;
        }
        // 更新机构下的前置版本号status为禁用
        systemConfigMapper.update(new LambdaUpdateWrapper<SystemConfigDO>()
                .eq(SystemConfigDO::getOrganId, OrganContextHolder.getOrganId())
                .eq(SystemConfigDO::getStatus, CommonStatusEnum.ENABLE.getStatus())
                .eq(SystemConfigDO::getType, SystemConfigTypeEnum.CUSTOM_PLATE_NO.getType())
                .lt(SystemConfigDO::getVersion, currentVersion)
                .set(SystemConfigDO::getStatus, CommonStatusEnum.DISABLE.getStatus()));
        // 删除本次版本号往前10个以外的配置
        if (minReserveVersion != 0) {
            systemConfigMapper.delete(new LambdaUpdateWrapper<SystemConfigDO>()
                    .eq(SystemConfigDO::getOrganId, OrganContextHolder.getOrganId())
                    .eq(SystemConfigDO::getType, SystemConfigTypeEnum.CUSTOM_PLATE_NO.getType())
                    .le(SystemConfigDO::getVersion, minReserveVersion));
        }
        // 移除机构下的板编号配置缓存
        // 禁用配置移除缓存
        String redisKey = String.format("%s:%d:%s", RedisKeyConstants.SYSTEM_CONFIG, OrganContextHolder.getOrganId(), RedisKeyConstants.CUSTOM_PLATE_NO);
        Boolean delete = stringRedisTemplate.delete(redisKey);
        log.info("[CustomPlateNoGenerateService][afterUpdateStatus]key：{}缓存删除结果：{}", redisKey, delete);

        // 查询机构下全局序号
        CustomPlateNoSeqDO plateNoSeqByConfigId = customPlateNoSeqService.getOrgCustomPlateNoSeq();
        // 提前生成板编号序号，存在则不处理
        if (ObjectUtil.isNull(plateNoSeqByConfigId)) {
            customPlateNoSeqMapper.insert(new CustomPlateNoSeqDO());
        }
    }


    @Override
    public void deleteConfig(ConfigDeleteReqVO reqVO) {
        // TODO document why this method is empty
    }


    @Override
    public void updateConfigStatus(ConfigUpdateStatusReqVO reqVO) {
        Long id = reqVO.getId();
        // 状态
        Integer status = reqVO.getStatus();
        // 组织
        Long organId = OrganContextHolder.getOrganId();

        // 校验存在
        SystemConfigDO systemConfigDO = systemConfigMapper.selectOne(new LambdaQueryWrapperX<SystemConfigDO>()
                .eq(SystemConfigDO::getId, id)
                .eq(SystemConfigDO::getOrganId, OrganContextHolder.getOrganId()));
        if (ObjectUtil.isNull(systemConfigDO)) {
            throw new ServiceException(SYSTEM_CONFIG_NOT_EXISTS);
        }

        if (CommonStatusEnum.ENABLE.getStatus().equals(status)) {
            // 查询最大版本号
            List<SystemConfigDO> systemConfigDOS = systemConfigMapper.selectList(new LambdaQueryWrapperX<SystemConfigDO>()
                    .eq(SystemConfigDO::getType, SystemConfigTypeEnum.CUSTOM_PLATE_NO.getType())
                    .eq(SystemConfigDO::getOrganId, OrganContextHolder.getOrganId())
                    .orderByAsc(SystemConfigDO::getVersion));
            Optional<SystemConfigDO> maxVersionCustPlateNoConfigOptinal = systemConfigDOS.stream()
                    .max(Comparator.comparing(SystemConfigDO::getVersion));
            if (maxVersionCustPlateNoConfigOptinal.isPresent()) {
                // 启用配置，启用最大版本号
                systemConfigMapper.update(new LambdaUpdateWrapper<SystemConfigDO>()
                        .eq(SystemConfigDO::getOrganId, organId)
                        .eq(SystemConfigDO::getId, maxVersionCustPlateNoConfigOptinal.get().getId())
                        .eq(SystemConfigDO::getType, SystemConfigTypeEnum.CUSTOM_PLATE_NO.getType())
                        .set(SystemConfigDO::getStatus, status));
            }
        } else {
            // 禁用配置，禁用组织下所有板编号配置
            systemConfigMapper.update(new LambdaUpdateWrapper<SystemConfigDO>()
                    .eq(SystemConfigDO::getOrganId, organId)
                    .eq(SystemConfigDO::getType, SystemConfigTypeEnum.CUSTOM_PLATE_NO.getType())
                    .set(SystemConfigDO::getStatus, status));

            // 禁用配置移除缓存
            String redisKey = String.format("%s:%d:%s", RedisKeyConstants.SYSTEM_CONFIG, organId, RedisKeyConstants.CUSTOM_PLATE_NO);
            Boolean delete = stringRedisTemplate.delete(redisKey);
            log.info("[CustomPlateNoGenerateService][afterUpdateStatus]key：{}缓存删除结果：{}", redisKey, delete);
        }

    }

    @Override
    public void updateConfigSort(List<ConfigUpdateSortReqVO> reqVO) {
        // TODO document why this method is empty
    }


    @Override
    public SystemConfigDO getSystemConfig(Long id) {

        SystemConfigDO systemConfigDO = systemConfigMapper.selectOne(new LambdaQueryWrapperX<SystemConfigDO>()
                .eq(SystemConfigDO::getId, id)
                .eq(SystemConfigDO::getOrganId, OrganContextHolder.getOrganId()));
        if (ObjectUtil.isNull(systemConfigDO)) {
            throw new ServiceException(SYSTEM_CONFIG_NOT_EXISTS);
        }

        return systemConfigDO;

    }

    @Override
    public void modifySystemConfig(ConfigSaveReqVO reqVO) {

        // 记录当前版本配置状态
        int status = ObjectUtil.isNotNull(reqVO.getId()) ? getSystemConfig(reqVO.getId()).getStatus() : CommonStatusEnum.ENABLE.getStatus();
        // 校验规则
        checkValid(reqVO.getSetting());
        // 系统配置保存前操作
        beforeSaveConfig(reqVO);
        SystemConfigDO systemConfigDO;
        if (ObjectUtil.isNotNull(reqVO.getId())) {
            systemConfigDO = getSystemConfig(reqVO.getId());
            // 覆盖配置
            systemConfigDO.setSetting(reqVO.getSetting());
            // 覆盖名称
            systemConfigDO.setName(reqVO.getName());
            // 更新
            systemConfigMapper.updateById(systemConfigDO);
        } else {
            systemConfigDO = BeanUtils.toBean(reqVO, SystemConfigDO.class).setStatus(status);
            // 新增
            systemConfigMapper.insert(systemConfigDO);
        }
        // 系统配置保存后操作
        afterSaveConfig(systemConfigDO, reqVO);

    }
}
