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

import cn.hutool.core.collection.CollUtil;
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.util.ServiceExceptionUtil;
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.executor.dal.dataobject.order.OrderDO;
import com.cf.imes.module.executor.dal.dataobject.plate.PlateDO;
import com.cf.imes.module.executor.dal.mysql.order.OrderMapper;
import com.cf.imes.module.executor.service.customplateno.vo.CustomPlateNoGenerateConfigVO;
import com.cf.imes.module.executor.service.customplateno.vo.CustomPlateNoRuleVO;
import com.cf.imes.module.executor.service.customplateno.vo.OrderCustomPlateNoSeqBodyVO;
import com.cf.imes.module.executor.service.customplateno.vo.OrderCustomPlateNoSeqRoomVO;
import com.cf.imes.module.executor.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.ArrayList;
import java.util.List;
import java.util.Optional;

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

/**
 * @author Gqr
 * @since 2024/11/20 15:28
 */
@Service("plateNoGenerateRuleService")
public class PlateNoGenerateRuleServiceImpl 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.PLATENO.getRuleCode(), ruleCode);
    }

    /**
     * 初始化生成所需配置
     *
     * @param generateConfigVO
     */
    private void initConfig(CustomPlateNoGenerateConfigVO generateConfigVO) {
        OrderCustomPlateNoSeqVO orderCustomPlateNoSeqVO = generateConfigVO.getOrderCustomPlateNoSeqVO();
        if (ObjectUtil.isNull(orderCustomPlateNoSeqVO)) {
            orderCustomPlateNoSeqVO = new OrderCustomPlateNoSeqVO();
            generateConfigVO.setOrderCustomPlateNoSeqVO(orderCustomPlateNoSeqVO);
        }
        List<OrderCustomPlateNoSeqRoomVO> rooms = orderCustomPlateNoSeqVO.getRooms();
        if (CollUtil.isEmpty(rooms)) {
            rooms = new ArrayList<>();
            orderCustomPlateNoSeqVO.setRooms(rooms);
        }
    }

    @Override
    public CustomPlateNoGenerateConfigVO generateNo(Long orderId, CustomPlateNoRuleVO plateNoRule, CustomPlateNoGenerateConfigVO generateConfig, PlateDO plateDO, boolean firstPlate) {
        // 初始化配置
        initConfig(generateConfig);
        // 按复位模式走不同的生成方式
        ResetModeEnum resetModeEnum = ResetModeEnum.getByMode(plateNoRule.getResetMode());
        if (ObjectUtil.equal(ResetModeEnum.ORDER, resetModeEnum)) {
            return generateNoByOrderResetMode(orderId, plateNoRule, generateConfig, plateDO, firstPlate);
        } else if (ObjectUtil.equal(ResetModeEnum.ROOM, resetModeEnum)) {
            return generateNoByRoomResetMode(plateNoRule, generateConfig, plateDO);
        } else if (ObjectUtil.equal(ResetModeEnum.BODY, resetModeEnum)) {
            return generateNoByBodyResetMode(plateNoRule, generateConfig, plateDO);
        } else if (ObjectUtil.equal(ResetModeEnum.YEAR, resetModeEnum) || ObjectUtil.equal(ResetModeEnum.MONTH, resetModeEnum) || ObjectUtil.equal(ResetModeEnum.DAY, resetModeEnum)) {
            return generateNoByDateResetMode(resetModeEnum, plateNoRule, generateConfig, plateDO);
        } else {
            throw ServiceExceptionUtil.exception(CUSTOM_PLATENO_GENERATE_PLATE_RULE_NOT_SUPPORT_RESETMODE, plateNoRule.getResetMode());
        }
    }

    @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()));

        ResetModeEnum resetModeEnum = ResetModeEnum.getByMode(ruleDTO.getResetMode());
        // 根据复位模式更新生产单的序号
        for (OrderDO orderDO : orderDOS) {
            OrderCustomPlateNoSeqVO orderCustomPlateNoSeqVO = JSON.parseObject(orderDO.getCustomPlatenoSeq(), OrderCustomPlateNoSeqVO.class);
            if (ObjectUtil.isNotNull(orderCustomPlateNoSeqVO)) {
                if (ObjectUtil.equal(ResetModeEnum.ORDER, resetModeEnum)) {
                    orderCustomPlateNoSeqVO.setPlateNoSeq(null);
                } else if (ObjectUtil.equal(ResetModeEnum.ROOM, resetModeEnum)) {
                    resetRoomPlateSeq(orderCustomPlateNoSeqVO.getRooms());
                } else if (ObjectUtil.equal(ResetModeEnum.BODY, resetModeEnum)) {
                    resetBodyPlateSeq(orderCustomPlateNoSeqVO.getRooms());
                }
                orderMapper.update(new LambdaUpdateWrapper<OrderDO>().eq(OrderDO::getId, orderDO.getId()).set(OrderDO::getCustomPlatenoSeq, JsonUtils.zipString(JSON.toJSONString(orderCustomPlateNoSeqVO))));
            }
        }
    }

    /**
     * 复位生产单下房间中的板件序号
     *
     * @param rooms
     */
    private void resetRoomPlateSeq(List<OrderCustomPlateNoSeqRoomVO> rooms) {
        if (CollUtil.isNotEmpty(rooms)) {
            for (OrderCustomPlateNoSeqRoomVO roomVO : rooms) {
                roomVO.setPlateNoSeq(null);
            }
        }
    }

    /**
     * 复位生产单下柜体中的板件序号
     *
     * @param rooms
     */
    private void resetBodyPlateSeq(List<OrderCustomPlateNoSeqRoomVO> rooms) {
        if (CollUtil.isNotEmpty(rooms)) {
            for (OrderCustomPlateNoSeqRoomVO roomVO : rooms) {
                List<OrderCustomPlateNoSeqBodyVO> bodys = roomVO.getBodys();
                if (CollUtil.isNotEmpty(bodys)) {
                    for (OrderCustomPlateNoSeqBodyVO bodyVO : bodys) {
                        bodyVO.setPlateNoSeq(null);
                    }
                }
            }
        }
    }

    /**
     * 按年/月/日复位模式下的板编号生成
     */
    private CustomPlateNoGenerateConfigVO generateNoByDateResetMode(ResetModeEnum resetModeEnum, CustomPlateNoRuleVO plateNoRule, CustomPlateNoGenerateConfigVO generateConfig, PlateDO plateDO) {
        // 机构下的自定义板编号序号
        CustomPlateNoSeqDTO orgCustomPlateNoSeqRespDTO = generateConfig.getOrgCustomPlateNoSeqRespDTO();
        // 从全局配置获取当前序号，取不到用初始值
        Integer orderNoSeq = orgCustomPlateNoSeqRespDTO.getPlateNoSeq();
        if (ObjectUtil.isNull(orderNoSeq)) {
            orderNoSeq = plateNoRule.getInitValue() - plateNoRule.getIncrementStep();
        }

        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);
        }
        // 补零
        String noPartAfterFillZero = fillZero(orderNoSeq, plateNoRule);
        plateDO.getCustomPlateNoBuilder().append(noPartAfterFillZero);

        orgCustomPlateNoSeqRespDTO.setPlateNoSeq(orderNoSeq);
        return generateConfig;
    }

    /**
     * 按生产单复位模式下的板编号生成
     *
     * @param orderId
     * @param plateNoRule
     * @param generateConfig
     * @param plateDO
     */
    private CustomPlateNoGenerateConfigVO generateNoByOrderResetMode(Long orderId, CustomPlateNoRuleVO plateNoRule, CustomPlateNoGenerateConfigVO generateConfig, PlateDO plateDO, boolean firstPlate) {
        Integer incrementStep = plateNoRule.getIncrementStep();
        Integer initValue = plateNoRule.getInitValue() - incrementStep;
        // 生产单下的序号
        OrderCustomPlateNoSeqVO orderCustomPlateNoSeqVO = generateConfig.getOrderCustomPlateNoSeqVO();
        // 机构下的自定义板编号序号
        CustomPlateNoSeqDTO orgCustomPlateNoSeqRespDTO = generateConfig.getOrgCustomPlateNoSeqRespDTO();
        // 获取当前生产单下板件序号
        Integer orderPlateNoSeq = Optional.ofNullable(orderCustomPlateNoSeqVO.getPlateNoSeq()).orElse(initValue);
        // 上次导入的生产单号
        Long lastOrderNo = orgCustomPlateNoSeqRespDTO.getLastOrderNo();
        if (firstPlate && (ObjectUtil.isNull(lastOrderNo) || ObjectUtil.notEqual(orderId, lastOrderNo))) {
            // 跨单复位到初始值
            orderPlateNoSeq = initValue;
        }
        // 跨板件累加步长，补零
        orderPlateNoSeq += incrementStep;
        plateDO.getCustomPlateNoBuilder().append(fillZero(orderPlateNoSeq, plateNoRule));
        // 累加后的值同步到当前生产单序号中
        orderCustomPlateNoSeqVO.setPlateNoSeq(orderPlateNoSeq);
        return generateConfig;
    }

    /**
     * 按房间复位模式下的板编号生成
     *
     * @param plateNoRule
     * @param generateConfig
     * @param plateDO
     * @return
     */
    private CustomPlateNoGenerateConfigVO generateNoByRoomResetMode(CustomPlateNoRuleVO plateNoRule, CustomPlateNoGenerateConfigVO generateConfig, PlateDO plateDO) {
        Integer incrementStep = plateNoRule.getIncrementStep();
        Integer initValue = plateNoRule.getInitValue() - incrementStep;
        // 生产单下的序号
        OrderCustomPlateNoSeqVO orderCustomPlateNoSeqVO = generateConfig.getOrderCustomPlateNoSeqVO();
        List<OrderCustomPlateNoSeqRoomVO> rooms = orderCustomPlateNoSeqVO.getRooms();
        String roomName = plateDO.getRoomName();
        // 根据房间名获取生产单下序号json中的房间下的加工组序号
        OrderCustomPlateNoSeqRoomVO roomSeqVo = getSeqRoomByRoomName(roomName, rooms);
        // 为空初始化，加入列表
        if (roomSeqVo == null) {
            roomSeqVo = OrderCustomPlateNoSeqRoomVO.builder()
                    .roomName(roomName)
                    .bodys(new ArrayList<>())
                    .build();
            rooms.add(roomSeqVo);
        }
        // 获取当前房间下板件序号
        // 累加步长
        Integer roomPlateNoSeq = Optional.ofNullable(roomSeqVo.getPlateNoSeq())
                .orElse(initValue) + incrementStep;
        // 累加后的值同步到当前生产单序号中
        roomSeqVo.setPlateNoSeq(roomPlateNoSeq);
        // 补零
        plateDO.getCustomPlateNoBuilder().append(fillZero(roomPlateNoSeq, plateNoRule));
        return generateConfig;
    }

    /**
     * 根据房间名从生产单序号json中获取房间序号列表
     *
     * @param roomName
     * @param roomVOList
     * @return
     */
    private OrderCustomPlateNoSeqRoomVO getSeqRoomByRoomName(String roomName, List<OrderCustomPlateNoSeqRoomVO> roomVOList) {
        return roomVOList.stream().filter(roomVO -> ObjectUtil.equal(roomName, roomVO.getRoomName())).findAny().orElse(null);
    }

    /**
     * 按柜体复位模式下的板编号生成
     *
     * @param plateNoRule
     * @param generateConfig
     * @param plateDO
     * @return
     */
    private CustomPlateNoGenerateConfigVO generateNoByBodyResetMode(CustomPlateNoRuleVO plateNoRule, CustomPlateNoGenerateConfigVO generateConfig, PlateDO plateDO) {
        Integer incrementStep = plateNoRule.getIncrementStep();
        Integer initValue = plateNoRule.getInitValue() - incrementStep;
        // 生产单下的序号
        OrderCustomPlateNoSeqVO orderCustomPlateNoSeqVO = generateConfig.getOrderCustomPlateNoSeqVO();
        List<OrderCustomPlateNoSeqRoomVO> rooms = orderCustomPlateNoSeqVO.getRooms();

        String roomName = plateDO.getRoomName();
        // 根据房间名获取生产单下序号json中的房间下的加工组序号
        OrderCustomPlateNoSeqRoomVO roomSeqVo = getSeqRoomByRoomName(roomName, rooms);
        if (ObjectUtil.isNull(roomSeqVo)) {
            // 房间为空，new房间
            roomSeqVo = OrderCustomPlateNoSeqRoomVO.
                    builder()
                    .roomName(roomName)
                    .bodys(new ArrayList<>())
                    .build();
            rooms.add(roomSeqVo);
        }

        String bodyName = plateDO.getBodyName();
        // 根据柜体名获取生产单下序号json中的房间下的加工组序号
        OrderCustomPlateNoSeqBodyVO bodySeqVO = getBodySeqByBodyName(bodyName, roomSeqVo);

        if (bodySeqVO == null) {
            // 柜体为空，new柜体
            bodySeqVO = OrderCustomPlateNoSeqBodyVO.builder()
                    .bodyName(bodyName)
                    .build();
            roomSeqVo.getBodys().add(bodySeqVO);
        }

        // 累加步长
        // 获取柜体下的板件序号
        Integer bodyPlateNoSeq = Optional.ofNullable(bodySeqVO.getPlateNoSeq()).orElse(initValue) + incrementStep;
        // 累加后的值同步到当前生产单序号中
        bodySeqVO.setPlateNoSeq(bodyPlateNoSeq);
        // 补零
        String noPartAfterFillZero = fillZero(bodyPlateNoSeq, plateNoRule);
        plateDO.getCustomPlateNoBuilder().append(noPartAfterFillZero);
        return generateConfig;
    }

    /**
     * 根据房间名从生产单序号json中获取房间序号列表
     *
     * @param bodyName
     * @param roomVO
     * @return
     */
    private OrderCustomPlateNoSeqBodyVO getBodySeqByBodyName(String bodyName, OrderCustomPlateNoSeqRoomVO roomVO) {
        List<OrderCustomPlateNoSeqBodyVO> bodys = roomVO.getBodys();
        if (ObjectUtil.isNotNull(bodys)) {
            for (OrderCustomPlateNoSeqBodyVO bodyVO : bodys) {
                if (ObjectUtil.equal(bodyVO.getBodyName(), bodyName)) {
                    return bodyVO;
                }
            }
        } else {
            bodys = new ArrayList<>();
            roomVO.setBodys(bodys);
        }
        return null;
    }

    /**
     * 按年复位
     *
     * @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)) {
            // 跨年，把上一次的年设成当前年，后续不再跨年
            orgCustomPlateNoSeqRespDTO.setLastYear(Integer.parseInt(nowYearFormat));
            // 复位
            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)) {
            // 跨月，把上一次的月设成当前月，后续不再跨月
            orgCustomPlateNoSeqRespDTO.setLastMonth(Integer.parseInt(nowMonthFormat));
            // 复位
            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)) {
            // 跨月，把上一次的月设成当前月，后续不再跨月
            orgCustomPlateNoSeqRespDTO.setLastDay(Integer.parseInt(nowDayFormat));
            // 复位
            return initValue;
        }
        return curr + plateNoRule.getIncrementStep();
    }
}
