package com.cf.imes.module.plan.service.customplatenorule;

import cn.hutool.core.util.ObjectUtil;
import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.cf.imes.framework.common.exception.ServiceException;
import com.cf.imes.framework.common.util.json.JsonUtils;
import com.cf.imes.framework.organ.core.context.OrganContextHolder;
import com.cf.imes.module.executor.api.customplateno.dto.CustomPlateNoRuleDTO;
import com.cf.imes.module.plan.dal.dataobject.order.OrderDO;
import com.cf.imes.module.plan.dal.dataobject.plate.PlateDO;
import com.cf.imes.module.plan.dal.mysql.order.OrderMapper;
import com.cf.imes.module.plan.service.customplateno.vo.CustomPlateNoGenerateConfigVO;
import com.cf.imes.module.plan.service.customplateno.vo.CustomPlateNoRuleVO;
import com.cf.imes.module.plan.service.customplateno.vo.OrderCustomPlateNoSeqVO;
import com.cf.imes.module.system.api.customplateno.dto.CustomPlateNoSeqDTO;
import com.cf.imes.module.system.enums.customplateno.CustomPlateNoRuleCodeEnum;
import com.cf.imes.module.system.enums.customplateno.ResetModeEnum;
import org.springframework.stereotype.Service;

import jakarta.annotation.Resource;
import java.time.format.DateTimeFormatter;
import java.util.List;
import java.util.Optional;

import static com.cf.imes.module.executor.enums.ErrorCodeConstants.CUSTOM_PLATENO_GENERATE_ORDERNO_RULE_NOT_SUPPORT_RESETMODE;

/**
 * 订单序号生成规则服务实现类
 *
 * @author Gqr
 * @since 2024/11/18 17:18
 */
@Service("orderNoGenerateRuleService")
public class OrderNoGenerateRuleServiceImpl implements CustomPlateNoGenerateRuleService {

    private static final DateTimeFormatter YEAR_FORMATTER = DateTimeFormatter.ofPattern("yyyy");
    private static final DateTimeFormatter MONTH_FORMATTER = DateTimeFormatter.ofPattern("yyyyMM");
    private static final DateTimeFormatter DAY_FORMATTER = DateTimeFormatter.ofPattern("yyyyMMdd");

    @Resource
    private OrderMapper orderMapper;

    @Override
    public boolean match(String ruleCode) {
        return ObjectUtil.equal(CustomPlateNoRuleCodeEnum.ORDERNO.getRuleCode(), ruleCode);
    }

    /**
     * 初始化生成所需配置
     *
     * @param generateConfigVO
     */
    private static void initConfig(CustomPlateNoGenerateConfigVO generateConfigVO) {
        OrderCustomPlateNoSeqVO orderCustomPlateNoSeqVO = generateConfigVO.getOrderCustomPlateNoSeqVO();
        if (ObjectUtil.isNull(orderCustomPlateNoSeqVO)) {
            orderCustomPlateNoSeqVO = new OrderCustomPlateNoSeqVO();
            generateConfigVO.setOrderCustomPlateNoSeqVO(orderCustomPlateNoSeqVO);
        }
    }

    @Override
    public CustomPlateNoGenerateConfigVO generateNo(Long orderId, CustomPlateNoRuleVO plateNoRule, CustomPlateNoGenerateConfigVO generateConfig, PlateDO plateDO, boolean firstPlate) {
        // 初始化配置
        initConfig(generateConfig);
        // 订单下的序号
        OrderCustomPlateNoSeqVO orderCustomPlateNoSeqVO = generateConfig.getOrderCustomPlateNoSeqVO();
        Integer orderNoSeq = orderCustomPlateNoSeqVO.getOrderNoSeq();
        // 当前导入已有序号的，订单内订单序号不会再变直接用
        if (ObjectUtil.isNotNull(orderNoSeq)) {
            // 补零
            String noPartAfterFill = this.fillZero(orderNoSeq, plateNoRule);
            plateDO.getCustomPlateNoBuilder().append(noPartAfterFill);
            return generateConfig;
        }
        // 机构下的自定义板编号序号
        CustomPlateNoSeqDTO orgCustomPlateNoSeqRespDTO = generateConfig.getOrgCustomPlateNoSeqRespDTO();
        // 获取当前序号值
        int currOrderNoSeq = Optional.ofNullable(orgCustomPlateNoSeqRespDTO.getOrderNoSeq()).orElse(plateNoRule.getInitValue() - plateNoRule.getIncrementStep());
        // 上次导入的订单号
        Long lastOrderNo = orgCustomPlateNoSeqRespDTO.getLastOrderNo();
        if (firstPlate && (ObjectUtil.isNull(lastOrderNo) || ObjectUtil.notEqual(orderId, lastOrderNo))) {
            // 根据复位模式计算序号
            currOrderNoSeq = generateNoByResetMode(currOrderNoSeq, ResetModeEnum.getByMode(plateNoRule.getResetMode()), plateNoRule, orgCustomPlateNoSeqRespDTO);
        }
        // 补零
        String noPartAfterFill = this.fillZero(currOrderNoSeq, plateNoRule);
        plateDO.getCustomPlateNoBuilder().append(noPartAfterFill);

        // 累加后的值同步到当前订单序号和机构序号中
        orderCustomPlateNoSeqVO.setOrderNoSeq(currOrderNoSeq);
        orgCustomPlateNoSeqRespDTO.setOrderNoSeq(currOrderNoSeq);
        return generateConfig;
    }

    @Override
    public void reset(CustomPlateNoRuleDTO ruleDTO) {
        // 查询所有使用当前配置id的订单列表
        Long configId = ruleDTO.getConfigId();
        List<OrderDO> orderDOS = orderMapper.selectList(
                new LambdaQueryWrapper<OrderDO>().eq(OrderDO::getCustomPlatenoConfigId, configId).eq(OrderDO::getOrganId, OrganContextHolder.getOrganId()));

        // 更新订单的序号
        for (OrderDO orderDO : orderDOS) {
            OrderCustomPlateNoSeqVO orderCustomPlateNoSeqVO = JSON.parseObject(orderDO.getCustomPlatenoSeq(), OrderCustomPlateNoSeqVO.class);
            if (ObjectUtil.isNotNull(orderCustomPlateNoSeqVO)) {
                orderCustomPlateNoSeqVO.setOrderNoSeq(null);
                orderMapper.update(new LambdaUpdateWrapper<OrderDO>().eq(OrderDO::getId, orderDO.getId()).set(OrderDO::getCustomPlatenoSeq, JsonUtils.zipString(JSON.toJSONString(orderCustomPlateNoSeqVO))));
            }
        }
    }

    /**
     * 基于复位模式的板编号生成
     *
     * @param orderNoSeq
     * @param resetModeEnum
     * @param plateNoRule
     * @param orgCustomPlateNoSeqRespDTO
     * @return 循环累加后的序号
     */
    private int generateNoByResetMode(int orderNoSeq, ResetModeEnum resetModeEnum, CustomPlateNoRuleVO plateNoRule, CustomPlateNoSeqDTO orgCustomPlateNoSeqRespDTO) {
        // 根据不同复位模式生成序号
        if (ObjectUtil.equal(ResetModeEnum.DIGIT, resetModeEnum)) {
            orderNoSeq = resetByLength(orderNoSeq, plateNoRule);
        } else if (ObjectUtil.equal(ResetModeEnum.YEAR, resetModeEnum)) {
            orderNoSeq = resetByYear(orderNoSeq, orgCustomPlateNoSeqRespDTO, plateNoRule);
        } else if (ObjectUtil.equal(ResetModeEnum.MONTH, resetModeEnum)) {
            orderNoSeq = resetByMonth(orderNoSeq, orgCustomPlateNoSeqRespDTO, plateNoRule);
        } else if (ObjectUtil.equal(ResetModeEnum.DAY, resetModeEnum)) {
            orderNoSeq = resetByDay(orderNoSeq, orgCustomPlateNoSeqRespDTO, plateNoRule);
        } else {
            throw new ServiceException(CUSTOM_PLATENO_GENERATE_ORDERNO_RULE_NOT_SUPPORT_RESETMODE, plateNoRule.getResetMode());
        }
        return orderNoSeq;
    }

    /**
     * 按位数复位
     *
     * @param curr        当前值
     * @param plateNoRule 规则配置
     */
    private int resetByLength(int curr, CustomPlateNoRuleVO plateNoRule) {
        // 位数下的最大值 10的length次方-1
        int maxNum = (int) (Math.pow(10, plateNoRule.getLength()) - 1);
        // 加上步长后的下一个序号
        int nextValue = curr + plateNoRule.getIncrementStep();
        // 超过最大值复位到初始值，没超过就继续下一个
        if (nextValue > maxNum) {
            return plateNoRule.getInitValue();
        } else {
            return nextValue;
        }
    }

    /**
     * 按年复位
     *
     * @param curr
     * @param orgCustomPlateNoSeqRespDTO
     * @param plateNoRule
     * @return
     */
    private int resetByYear(int curr, CustomPlateNoSeqDTO orgCustomPlateNoSeqRespDTO, CustomPlateNoRuleVO plateNoRule) {
        // 上一次的年
        Integer lastYear = orgCustomPlateNoSeqRespDTO.getLastYear();
        // 初始值
        Integer initValue = plateNoRule.getInitValue();
        String nowYearFormat = plateNoRule.getNow().format(YEAR_FORMATTER);
        if (ObjectUtil.notEqual(String.valueOf(lastYear), nowYearFormat)) {
            int nowDayNum = Integer.parseInt(nowYearFormat);
            // 跨年，把上一次的年设成当前年，后续不再跨年
            orgCustomPlateNoSeqRespDTO.setLastYear(nowDayNum);
            // 复位
            return initValue;
        }
        return curr + plateNoRule.getIncrementStep();
    }

    /**
     * 按月复位
     *
     * @param curr
     * @param orgCustomPlateNoSeqRespDTO
     * @param plateNoRule
     * @return
     */
    private int resetByMonth(int curr, CustomPlateNoSeqDTO orgCustomPlateNoSeqRespDTO, CustomPlateNoRuleVO plateNoRule) {
        // 上一次的月
        Integer lastMonth = orgCustomPlateNoSeqRespDTO.getLastMonth();
        // 初始值
        Integer initValue = plateNoRule.getInitValue();
        String nowMonthFormat = plateNoRule.getNow().format(MONTH_FORMATTER);
        if (ObjectUtil.notEqual(String.valueOf(lastMonth), nowMonthFormat)) {
            int nowDayNum = Integer.parseInt(nowMonthFormat);
            // 跨月，把上一次的月设成当前月，后续不再跨月
            orgCustomPlateNoSeqRespDTO.setLastMonth(nowDayNum);
            // 复位
            return initValue;
        }
        return curr + plateNoRule.getIncrementStep();
    }

    /**
     * 按天复位
     *
     * @param curr
     * @param orgCustomPlateNoSeqRespDTO
     * @param plateNoRule
     * @return
     */
    private int resetByDay(int curr, CustomPlateNoSeqDTO orgCustomPlateNoSeqRespDTO, CustomPlateNoRuleVO plateNoRule) {
        // 上一次的天
        Integer lastDay = orgCustomPlateNoSeqRespDTO.getLastDay();
        // 初始值
        Integer initValue = plateNoRule.getInitValue();
        String nowDayFormat = plateNoRule.getNow().format(DAY_FORMATTER);
        if (ObjectUtil.notEqual(String.valueOf(lastDay), nowDayFormat)) {
            int nowDayNum = Integer.parseInt(nowDayFormat);
            // 跨月，把上一次的月设成当前月，后续不再跨月
            orgCustomPlateNoSeqRespDTO.setLastDay(nowDayNum);
            // 复位
            return initValue;
        }
        return curr + plateNoRule.getIncrementStep();
    }
}
