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

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.util.ObjectUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.cf.imes.framework.common.enums.DeletedCodeEnum;
import com.cf.imes.framework.common.exception.ServiceException;
import com.cf.imes.module.executor.controller.admin.manage.pack.heapsplit.HeapSplitSaveReqVO;
import com.cf.imes.module.executor.controller.admin.manage.pack.heapsplit.OrdersHeapSplitDetailRespVO;
import com.cf.imes.module.executor.controller.admin.manage.pack.vo.OrderPartsRespVO;
import com.cf.imes.module.executor.controller.admin.manage.pack.vo.PackagePartsSaveReqVO;
import com.cf.imes.module.executor.controller.admin.manage.pack.vo.PlateDetailsRespVO;
import com.cf.imes.module.executor.dal.dataobject.orderItem.OrderItemDO;
import com.cf.imes.module.executor.dal.dataobject.plate.PlateDO;
import com.cf.imes.module.executor.dal.mysql.orderItem.OrderItemMapper;
import com.cf.imes.module.executor.dal.mysql.orderParts.OrderPartsMapper;
import com.cf.imes.module.executor.dal.mysql.plate.PlateMapper;
import com.cf.imes.module.executor.enums.OrderPackageMethodEnum;
import com.cf.imes.module.executor.enums.heapsplit.HeapSplitStatusEnum;
import com.cf.imes.module.executor.service.order.OrderService;
import jakarta.annotation.Resource;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Collection;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.stream.Collectors;

import static com.cf.imes.module.executor.enums.ErrorCodeConstants.PARTS_HEAPSPLIT_ITEM_SOURCE_NOT_EXISTS;
import static com.cf.imes.module.executor.enums.ErrorCodeConstants.PARTS_HEAPSPLIT_NUM_NOT_ENOUGH;

/**
 * 分堆 ServiceImpl 接口实现类
 *
 * @author Gqr
 * @since 2026/3/10 17:53
 */
@Service
public class HeapSplitServiceImpl implements HeapSplitService {

    @Resource
    private OrderItemMapper orderItemMapper;

    @Resource
    private PlateMapper plateMapper;

    @Resource
    private OrderPartsMapper orderPartsMapper;

    @Resource
    private OrderService orderService;

    @Resource
    private PlateMapper orderPlateMapper;

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void saveHeapsplit(HeapSplitSaveReqVO reqVO) {
        Integer packMethod = reqVO.getPackMethod();
        List<Long> orderIds = reqVO.getOrderIds();
        // 更新板件分堆状态
        List<Long> plateNos = reqVO.getPlateNos();
        if (CollUtil.isNotEmpty(plateNos)) {
            List<List<Long>> platePartitions = CollUtil.split(plateNos, 1000);
            for (List<Long> batch : platePartitions) {
                List<Long> plateIds = orderPlateMapper.selectList(new LambdaQueryWrapper<PlateDO>()
                        .in(PlateDO::getPlateNo, batch)
                        .in(PlateDO::getOrderId, orderIds)
                        .eq(PlateDO::getDeleted, DeletedCodeEnum.NOT_DELETED.getStatus())
                        .select(PlateDO::getId)
                ).stream().map(PlateDO::getId).toList();
                if (CollectionUtil.isEmpty(plateIds)) {
                    continue;
                }
                orderItemMapper.update(new LambdaUpdateWrapper<OrderItemDO>()
                        .in(OrderItemDO::getOrderId, orderIds)
                        .in(OrderItemDO::getPlateId, plateIds)
                        .eq(OrderItemDO::getHeapSplitStatus, HeapSplitStatusEnum.NO.getStatus())
                        .set(OrderItemDO::getHeapSplitStatus, HeapSplitStatusEnum.YES.getStatus())
                );
            }
        }

        // 删除板件分堆状态
        List<Long> delPlateNos = reqVO.getDelPlateNos();
        if (CollUtil.isNotEmpty(delPlateNos)) {
            List<List<Long>> delPlatePartitions = CollUtil.split(delPlateNos, 1000);
            for (List<Long> batch : delPlatePartitions) {
                List<Long> plateIds = orderPlateMapper.selectList(new LambdaQueryWrapper<PlateDO>()
                        .in(PlateDO::getPlateNo, batch)
                        .in(PlateDO::getOrderId, orderIds)
                        .eq(PlateDO::getDeleted, DeletedCodeEnum.NOT_DELETED.getStatus())
                        .select(PlateDO::getId)
                ).stream().map(PlateDO::getId).toList();
                if (CollectionUtil.isEmpty(plateIds)) {
                    continue;
                }
                orderItemMapper.update(new LambdaUpdateWrapper<OrderItemDO>()
                        .in(OrderItemDO::getOrderId, orderIds)
                        .in(OrderItemDO::getPlateId, plateIds)
                        .eq(OrderItemDO::getHeapSplitStatus, HeapSplitStatusEnum.YES.getStatus())
                        .set(OrderItemDO::getHeapSplitStatus, HeapSplitStatusEnum.NO.getStatus())
                );
            }
        }

        // 删除配件分堆状态
        processParts(reqVO.getDelParts(), packMethod, orderIds, false);
        // 更新配件分堆状态
        processParts(reqVO.getParts(), packMethod, orderIds, true);
    }

    /**
     * 配件分堆状态和数量处理
     *
     * @param list
     * @param packMethod
     * @param orderIds
     * @param isAdd
     */
    private void processParts(
            List<PackagePartsSaveReqVO> list,
            Integer packMethod,
            List<Long> orderIds,
            boolean isAdd) {

        if (CollUtil.isEmpty(list)) {
            return;
        }

        Map<Long, List<PackagePartsSaveReqVO>> groupMap =
                list.stream().collect(Collectors.groupingBy(item -> getGroupKey(item, packMethod)));

        for (Map.Entry<Long, List<PackagePartsSaveReqVO>> entry : groupMap.entrySet()) {

            Long groupKey = entry.getKey();

            for (PackagePartsSaveReqVO vo : entry.getValue()) {

                LambdaQueryWrapper<OrderItemDO> wrapper = buildWrapper(
                        groupKey,
                        vo.getPartsId(),
                        packMethod,
                        orderIds,
                        isAdd // add才需要heapSplit过滤
                );

                List<OrderItemDO> orderItemDOS = orderItemMapper.selectList(wrapper);

                if (isAdd) {
                    allocateGroup(orderItemDOS, vo.getNum());
                } else {
                    restoreGroup(orderItemDOS);
                }
            }
        }
    }

    /**
     * 分组规则
     * @param item
     * @param packMethod
     * @return
     */
    private Long getGroupKey(PackagePartsSaveReqVO item, Integer packMethod) {
        if (ObjectUtil.equals(OrderPackageMethodEnum.ROOM_NAME.getMethod(), packMethod)) {
            return item.getRoomId();
        } else if (ObjectUtil.equals(OrderPackageMethodEnum.BODY_NAME.getMethod(), packMethod)) {
            return item.getBodyId();
        } else if (ObjectUtil.equals(OrderPackageMethodEnum.ORDER.getMethod(), packMethod)) {
            return item.getOrderId();
        }
        return 0L;
    }

    /**
     * 动态构建查询wrapper
     *
     * @param groupKey
     * @param partsId
     * @param packMethod
     * @param orderIds
     * @param filterHeapSplit
     * @return
     */
    private LambdaQueryWrapper<OrderItemDO> buildWrapper(
            Long groupKey,
            Long partsId,
            Integer packMethod,
            List<Long> orderIds,
            boolean filterHeapSplit) {

        LambdaQueryWrapper<OrderItemDO> wrapper = new LambdaQueryWrapper<>();

        // 有加工组的扣减groupId = 0的，没加工组的扣减groupId = null && compId = null的
        wrapper.eq(OrderItemDO::getPartsId, partsId)
                .and(w -> w.eq(OrderItemDO::getGroupId, 0)
                        .or(x -> x.isNull(OrderItemDO::getGroupId)
                                .isNull(OrderItemDO::getCompId)));

        if (filterHeapSplit) {
            wrapper.eq(OrderItemDO::getHeapSplitStatus, false);
        }

        if (ObjectUtil.equals(OrderPackageMethodEnum.ROOM_NAME.getMethod(), packMethod)) {
            wrapper.eq(OrderItemDO::getRoomId, groupKey)
                    .in(OrderItemDO::getOrderId, orderIds);
        } else if (ObjectUtil.equals(OrderPackageMethodEnum.BODY_NAME.getMethod(), packMethod)) {
            wrapper.eq(OrderItemDO::getBodyId, groupKey)
                    .in(OrderItemDO::getOrderId, orderIds);
        } else if (ObjectUtil.equals(OrderPackageMethodEnum.ORDER.getMethod(), packMethod)) {
            wrapper.eq(OrderItemDO::getOrderId, groupKey);
        }

        wrapper.orderByAsc(OrderItemDO::getNum);

        return wrapper;
    }

    @Override
    public OrdersHeapSplitDetailRespVO getOrdersHeapSplitedDetail(List<Long> orderIds) {
        OrdersHeapSplitDetailRespVO respVO = new OrdersHeapSplitDetailRespVO();
        // 查询多订单信息
        respVO.setOrders(orderService.getPackOrdersInfo(orderIds));
        // 查询板件
        List<PlateDetailsRespVO> plates = plateMapper.selectOrdersHeapSplitPlateList(orderIds);
        // 查询配件
        List<OrderPartsRespVO> parts = orderPartsMapper.selectOrdersHeapSplitPartsList(orderIds);

        respVO.setPlates(CollUtil.newArrayList(buildPlateGroup(plates)));
        respVO.setParts(CollUtil.newArrayList(buildPartsGroup(parts)));
        return respVO;
    }

    /**
     * 板件分组：加工组
     *
     * @param plates
     * @return
     */
    private Collection<PlateDetailsRespVO> buildPlateGroup( List<PlateDetailsRespVO> plates){
        Map<String, PlateDetailsRespVO> map = new LinkedHashMap<>();

        for (PlateDetailsRespVO row : plates) {

            // ===== 1. 组装 唯一key=====
            String key = row.getPlateId() + "_" + row.getRoomId() + "_" + row.getBodyId();

            PlateDetailsRespVO vo = map.computeIfAbsent(key, k -> {
                PlateDetailsRespVO newVo = new PlateDetailsRespVO();

                BeanUtils.copyProperties(row, newVo);

                // ===== 初始化 =====
                newVo.setProcessGroupNameList(new ArrayList<>());

                return newVo;
            });

            // ===== 2. 收集加工组（允许重复，不去重）=====
            if (row.getProcessGroup() != null) {
                vo.getProcessGroupNameList().add(row.getProcessGroup());
            }
        }

        Collection<PlateDetailsRespVO> values = map.values();
        // ===== 3. 转换成逗号字符串 =====
        for (PlateDetailsRespVO vo : values) {
            List<String> listGroup = vo.getProcessGroupNameList();

            // 拼接加工组
            if (listGroup != null && !listGroup.isEmpty()) {
                vo.setProcessGroup(String.join(",", listGroup));
            } else {
                vo.setProcessGroup("");
            }

            // 可释放内存
            vo.setProcessGroupNameList(null);

            // 成倍编号处理
            if (vo.getMultiNum() > 1) {
                vo.setCabinetName(
                        vo.getCabinetName() + "-" + vo.getMultiSort()
                );
            }
        }

        return values;
    }


    /**
     * 配件分组：加工组、部件（目前是一对一）
     *
     * @param parts
     * @return
     */
    private Collection<OrderPartsRespVO> buildPartsGroup(List<OrderPartsRespVO> parts) {

        Map<String, OrderPartsRespVO> map = new LinkedHashMap<>();

        for (OrderPartsRespVO row : parts) {

            // ===== 1. 分组 key =====
            String key = row.getPartsId()
                    + "_" + row.getRoomId()
                    + "_" + row.getBodyId()
                    + "_" + row.getHeapSplitStatus();

            OrderPartsRespVO vo = map.computeIfAbsent(key, k -> {
                OrderPartsRespVO v = new OrderPartsRespVO();
                BeanUtils.copyProperties(row, v);

                v.setNum(BigDecimal.ZERO);
                v.setHeapNum(BigDecimal.ZERO);
                v.setProcessGroupNameList(new ArrayList<>());
                v.setComponentNameList(new ArrayList<>());
                return v;
            });

            // ===== 3. num 累加 =====
            if (row.getNum() != null &&
                    (ObjectUtil.equals(row.getGroupId(), 0L) || (ObjectUtil.isNull(row.getGroupId()) && ObjectUtil.isNull(row.getComponentName())))) {
                vo.setNum(vo.getNum().add(row.getNum()));
            }

            // ===== 4. heapNum 累加 =====
            if (row.getHeapNum() != null) {
                vo.setHeapNum(vo.getHeapNum().add(row.getHeapNum()));
            }

            // ===== 5. 加工组（允许重复）=====
            if (row.getProcessGroup() != null) {
                vo.getProcessGroupNameList().add(row.getProcessGroup());
            }

            // ===== 6. 部件组（允许重复）=====
            if (row.getComponentName() != null) {
                vo.getComponentNameList().add(row.getComponentName());
            }
        }

        // ===== 7. 收尾处理 =====
        for (OrderPartsRespVO vo : map.values()) {

            // 加工组拼接
            List<String> processGroupNameList = vo.getProcessGroupNameList();
            if (CollUtil.isNotEmpty(processGroupNameList)) {
                vo.setProcessGroup(String.join(",", processGroupNameList));
            } else {
                vo.setProcessGroup("");
            }

            // ===== 部件组拼接 =====
            List<String> componentNameList = vo.getComponentNameList();
            if (CollUtil.isNotEmpty(componentNameList)) {
                vo.setComponentName(String.join(",", componentNameList));
            } else {
                vo.setComponentName(null);
            }

            // 可释放内存
            vo.setProcessGroupNameList(null);
            vo.setComponentNameList(null);

            // ===== multiSort 处理（柜体编号）=====
            if (vo.getMultiNum() > 1) {
                vo.setCabinetName(
                        vo.getCabinetName() + "-" + vo.getMultiSort()
                );
            } else {
                vo.setCabinetName(vo.getCabinetName());
            }
        }

        return map.values();
    }

    /**
     * 分堆打包数量
     *
     * @param list      同一查询范围的order_parts id相同的orderitem列表
     * @param targetNum 分配目标数
     */
    private void allocateGroup(List<OrderItemDO> list, int targetNum) {

        int remain = targetNum;

        for (OrderItemDO item : list) {

            if (remain <= 0) {
                break;
            }

            double current = item.getNum() - item.getHeapNum();
            if (current <= 0) {
                continue;
            }

            // 情况1：<= 直接吃掉（不拆分！）
            if (current <= remain) {

                // 标记分堆
                item.setHeapSplitStatus(HeapSplitStatusEnum.YES.getStatus());

                // 更新分堆数量
                item.setHeapNum(current);

                orderItemMapper.updateById(item);

                remain -= current;
            }

            // 情况2：> 需要拆分
            else {

                // 1、原记录累加分堆数量
                item.setHeapNum(item.getHeapNum() + remain);
                orderItemMapper.updateById(item);

                // 2、 新建分堆记录
                OrderItemDO newItem = buildHeapItem(item, remain);
                orderItemMapper.insert(newItem);

                remain = 0;
                break;
            }
        }

        if (remain > 0) {
            throw new ServiceException(PARTS_HEAPSPLIT_NUM_NOT_ENOUGH);
        }
    }

    /**
     * 分堆未全覆盖创建item副本
     *
     * @param source
     * @param heapNum
     * @return
     */
    private OrderItemDO buildHeapItem(OrderItemDO source, double heapNum) {
        OrderItemDO newItem = new OrderItemDO();

        // 字段复制
        BeanUtils.copyProperties(source, newItem);

        newItem.setId(null); // 新ID
        newItem.setHeapNum(heapNum);

        // 标记为“已分堆”
        newItem.setHeapSplitStatus(HeapSplitStatusEnum.YES.getStatus());
        newItem.setSourceId(source.getId());

        return newItem;
    }

    /**
     * 还原配件分堆数量
     *
     * @param list 同一查询范围的order_parts id相同的orderitem列表
     */
    private void restoreGroup(List<OrderItemDO> list) {

        List<Long> deleteIds = new ArrayList<>();
        List<OrderItemDO> updateList = new ArrayList<>();
        List<OrderItemDO> insertList = new ArrayList<>();

        Map<Long, List<OrderItemDO>> groupMap = list.stream()
                .collect(Collectors.groupingBy(i ->
                        ObjectUtil.equals(0L, i.getSourceId()) ? i.getId() : i.getSourceId()
                ));

        for (Map.Entry<Long, List<OrderItemDO>> entry : groupMap.entrySet()) {

            List<OrderItemDO> items = entry.getValue();

            // 找父
            OrderItemDO parent = items.stream()
                    .filter(i -> ObjectUtil.equals(0L, i.getSourceId()))
                    .findFirst()
                    .orElseThrow(() -> new ServiceException(PARTS_HEAPSPLIT_ITEM_SOURCE_NOT_EXISTS));

            // 找子
            List<OrderItemDO> subItems = items.stream()
                    .filter(i -> !ObjectUtil.equals(0L, i.getSourceId()))
                    .toList();

            double parentHeap = Optional.ofNullable(parent.getHeapNum()).orElse(0.0);
            double subTotal = subItems.stream()
                    .mapToDouble(i -> Optional.ofNullable(i.getHeapNum()).orElse(0.0))
                    .sum();


            if (CollUtil.isNotEmpty(subItems)) {
                // 有子
                if (ObjectUtil.equals(parent.getHeapSplitStatus(), HeapSplitStatusEnum.YES.getStatus())) {
                    // 父本身已分堆，则降级成子
                    parent.setSourceId(parent.getId());
                    updateList.add(parent);

                    // 增加一个父，数量是 num-原来的父的已分堆heapNum=现在
                    OrderItemDO newBase = new OrderItemDO();
                    BeanUtil.copyProperties(parent, newBase);

                    newBase.setId(null);
                    newBase.setSourceId(0L);
                    newBase.setHeapNum(parent.getNum() - subTotal);
                    newBase.setHeapSplitStatus(HeapSplitStatusEnum.NO.getStatus());
                    insertList.add(newBase);

                } else {
                    // 本身没分堆，把父的子heapNum扣掉
                    parent.setHeapNum(parentHeap - subTotal);
                    updateList.add(parent);
                }

                // 删除原来的子
                deleteIds.addAll(subItems.stream().map(OrderItemDO::getId).toList());

            } else {
                // 没有子，分堆了就还原数
                if (ObjectUtil.equals(parent.getHeapSplitStatus(), HeapSplitStatusEnum.YES.getStatus())) {
                    parent.setHeapNum(0.0);
                    parent.setHeapSplitStatus(HeapSplitStatusEnum.NO.getStatus());
                    updateList.add(parent);
                }
            }
        }

        // 执行数据库操作
        if (!updateList.isEmpty()) {
            orderItemMapper.updateBatch(updateList);
        }
        orderItemMapper.insertBatch(insertList);
        orderItemMapper.deleteByIds(deleteIds);
    }
}