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.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.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.util.ArrayList;
import java.util.List;
import java.util.Optional;

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

/**
 * 柜体序号生成规则服务实现类
 *
 * @author Gqr
 * @since 2024/11/19 16:35
 */
@Service("bodyNoGenerateRuleService")
public class BodyNoGenerateRuleServiceImpl implements CustomPlateNoGenerateRuleService {

    @Resource
    private OrderMapper orderMapper;

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

    /**
     * 初始化生成所需配置
     *
     * @param generateConfigVO
     */
    private static 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);
        }
        List<OrderCustomPlateNoSeqBodyVO> boyds = orderCustomPlateNoSeqVO.getBodys();
        if (CollUtil.isEmpty(boyds)) {
            boyds = new ArrayList<>();
            orderCustomPlateNoSeqVO.setBodys(boyds);
        }
    }

    @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)) {
            generateConfig = generateNoByOrderResetMode(orderId, plateNoRule, generateConfig, plateDO, firstPlate);
        } else if (ObjectUtil.equal(ResetModeEnum.ROOM, resetModeEnum)) {
            generateConfig = generateNoByRoomResetMode(plateNoRule, generateConfig, plateDO);
        } else {
            throw new ServiceException(CUSTOM_PLATENO_GENERATE_BODY_RULE_NOT_SUPPORT_RESETMODE, plateNoRule.getResetMode());
        }
        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()));

        ResetModeEnum resetModeEnum = ResetModeEnum.getByMode(ruleDTO.getResetMode());
        // 根据复位模式更新订单的序号
        for (OrderDO orderDO : orderDOS) {
            resetOrder(orderDO, resetModeEnum);
        }
    }

    private void resetOrder(OrderDO orderDO, ResetModeEnum resetModeEnum) {
        OrderCustomPlateNoSeqVO orderCustomPlateNoSeqVO = JSON.parseObject(orderDO.getCustomPlatenoSeq(), OrderCustomPlateNoSeqVO.class);
        if (ObjectUtil.isNotNull(orderCustomPlateNoSeqVO)) {
            if (ObjectUtil.equal(ResetModeEnum.ORDER, resetModeEnum)) {
                orderCustomPlateNoSeqVO.setBodyNoSeq(null);
            } else if (ObjectUtil.equal(ResetModeEnum.ROOM, resetModeEnum)) {
                List<OrderCustomPlateNoSeqRoomVO> rooms = orderCustomPlateNoSeqVO.getRooms();
                if (CollUtil.isNotEmpty(rooms)) {
                    for (OrderCustomPlateNoSeqRoomVO roomVO : rooms) {
                        roomVO.setBodyNoSeq(null);
                    }
                }
            }
            orderMapper.update(new LambdaUpdateWrapper<OrderDO>().eq(OrderDO::getId, orderDO.getId()).set(OrderDO::getCustomPlatenoSeq, JsonUtils.zipString(JSON.toJSONString(orderCustomPlateNoSeqVO))));
        }
    }

    /**
     * 按订单复位模式下的板编号生成
     *
     * @param orderId        订单号
     * @param plateNoRule    当前规则配置
     * @param generateConfig 生成规则配置
     * @param plateDO        板件列表
     * @return
     */
    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 orderBodyNoSeq = Optional.ofNullable(orderCustomPlateNoSeqVO.getBodyNoSeq()).orElse(initValue);
        // 订单序号下的房间序号列表
        List<OrderCustomPlateNoSeqBodyVO> bodys = orderCustomPlateNoSeqVO.getBodys();
        // 上次导入的订单号
        Long lastOrderNo = orgCustomPlateNoSeqRespDTO.getLastOrderNo();
        if (firstPlate && (ObjectUtil.isNull(lastOrderNo) || ObjectUtil.notEqual(orderId, lastOrderNo))) {
            // 跨单复位到初始值
            orderBodyNoSeq = initValue;
        }
        String bodyName = plateDO.getBodyName();
        // 根据柜体名获取订单下序号json中第一层柜体列表的柜体序号
        OrderCustomPlateNoSeqBodyVO bodySeqVo = getBodySeqVOByBodyName(bodyName, bodys);
        // 获取当前柜体序号值
        Integer bodyNoSeq = Optional.ofNullable(bodySeqVo).map(OrderCustomPlateNoSeqBodyVO::getBodyNoSeq).orElse(null);
        if (bodySeqVo == null) {
            // 订单序号下柜体为空，新建柜体，取订单下柜体序号
            bodySeqVo = OrderCustomPlateNoSeqBodyVO.builder()
                    .bodyName(bodyName)
                    .build();
            bodys.add(bodySeqVo);
            // 累加步长
            bodyNoSeq = orderBodyNoSeq + incrementStep;
            // 累加后的值同步到当前订单序号中，订单下柜体序号累加到多少了
            orderCustomPlateNoSeqVO.setBodyNoSeq(bodyNoSeq);
        } else if (bodyNoSeq == null) {
            // 柜体下序号为空，取订单下房间序号
            // 累加步长
            bodyNoSeq = orderBodyNoSeq + incrementStep;
            // 累加后的值同步到当前订单序号中，订单下柜体序号累加到多少了
            orderCustomPlateNoSeqVO.setBodyNoSeq(bodyNoSeq);
        }

        // 补零
        String noPartAfterFillZero = fillZero(bodyNoSeq, plateNoRule);
        plateDO.getCustomPlateNoBuilder().append(noPartAfterFillZero);
        // 累加后同步到json：柜体下累加到多少了
        bodySeqVo.setBodyNoSeq(bodyNoSeq);

        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 = getRoomSeqVOByRoomName(roomName, rooms);
        Integer roomBodyNoRoomSeq = Optional.ofNullable(roomSeqVo)
                .map(OrderCustomPlateNoSeqRoomVO::getBodyNoSeq)
                .orElse(initValue);

        if (roomSeqVo == null) {
            // 房间为空，新建对象，设置初始值
            roomSeqVo = OrderCustomPlateNoSeqRoomVO.builder()
                    .roomName(roomName)
                    .bodyNoSeq(roomBodyNoRoomSeq)
                    .bodys(new ArrayList<>())
                    .build();
            rooms.add(roomSeqVo);
        }

        // 如果是新的柜体vo，要把累加的值记录到订单rooms下的柜体
        String bodyName = plateDO.getBodyName();
        // 根据柜体名获取订单下序号中rooms下柜体列表的柜体序号
        List<OrderCustomPlateNoSeqBodyVO> roomBodys = roomSeqVo.getBodys();
        OrderCustomPlateNoSeqBodyVO roomBodySeqVo = getBodySeqVOByBodyName(bodyName, roomBodys);
        // 获取当前房间下柜体的序号值
        Integer roomBodyNoSeq = Optional.ofNullable(roomBodySeqVo).map(OrderCustomPlateNoSeqBodyVO::getBodyNoSeq).orElse(null);
        if (roomBodySeqVo == null) {
            // 房间下柜体为空，新建对象，设置房间下全局柜体序号值
            roomBodySeqVo = OrderCustomPlateNoSeqBodyVO.builder()
                    .bodyName(bodyName)
                    .build();
            roomBodys.add(roomBodySeqVo);
            // 累加步长
            roomBodyNoSeq = roomBodyNoRoomSeq + incrementStep;
            // 累加后的值同步到当前订单序号中，订单下房间中柜体累加到多少了
            roomSeqVo.setBodyNoSeq(roomBodyNoSeq);
        } else if (roomBodyNoSeq == null) {
            // 房间下柜体序号为空，设置房间下全局柜体序号值
            // 累加步长
            roomBodyNoSeq = roomBodyNoRoomSeq + incrementStep;
            // 累加后的值同步到当前订单序号中，订单下房间中柜体累加到多少了
            roomSeqVo.setBodyNoSeq(roomBodyNoSeq);
        }

        // 补零
        String noPartAfterFillZero = fillZero(roomBodyNoSeq, plateNoRule);
        plateDO.getCustomPlateNoBuilder().append(noPartAfterFillZero);
        // 累加后同步到json中，room下柜体累加到多少了
        roomBodySeqVo.setBodyNoSeq(roomBodyNoSeq);

        return generateConfig;
    }

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

    /**
     * 根据柜体名从订单序号json中获取柜体序号
     *
     * @param bodyName
     * @param bodyVOList
     * @return
     */
    private OrderCustomPlateNoSeqBodyVO getBodySeqVOByBodyName(String bodyName, List<OrderCustomPlateNoSeqBodyVO> bodyVOList) {
        if (CollUtil.isEmpty(bodyVOList)) {
            return null;
        }
        return bodyVOList.stream().filter(bodyVO -> ObjectUtil.equal(bodyName, bodyVO.getBodyName())).findAny().orElse(null);
    }
}
