package com.cf.imes.module.executor.service.manage.pack;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.text.CharSequenceUtil;
import cn.hutool.core.util.ArrayUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.PageDTO;
import com.cf.imes.framework.common.enums.*;
import com.cf.imes.framework.common.exception.ErrorCode;
import com.cf.imes.framework.common.exception.ServiceException;
import com.cf.imes.framework.common.pojo.PageResult;
import com.cf.imes.framework.common.util.Assert.AssertUtils;
import com.cf.imes.framework.id.core.util.SnowflakeIdWorker3rd;
import com.cf.imes.framework.mybatis.core.query.LambdaQueryWrapperX;
import com.cf.imes.module.executor.api.plan.OrderPlanApi;
import com.cf.imes.module.executor.controller.admin.manage.pack.vo.*;
import com.cf.imes.module.executor.controller.admin.manage.query.vo.pack.OrderPackageVO;
import com.cf.imes.module.executor.controller.admin.manage.query.vo.pack.PackageDetailsRespVO;
import com.cf.imes.module.executor.dal.dataobject.order.OrderDO;
import com.cf.imes.module.executor.dal.dataobject.orderItem.OrderItemDO;
import com.cf.imes.module.executor.dal.dataobject.orderParts.OrderPartsDO;
import com.cf.imes.module.executor.dal.dataobject.pack.OrderPackagDO;
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.dal.mysql.orderItem.OrderItemMapper;
import com.cf.imes.module.executor.dal.mysql.orderParts.OrderPartsMapper;
import com.cf.imes.module.executor.dal.mysql.pack.OrderPackageMapper;
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.pack.PackScanComponentCorrelationTypeEnum;
import com.cf.imes.module.executor.service.order.OrderInfoVersionControlService;
import com.cf.imes.module.executor.service.order.OrderService;
import com.cf.imes.module.executor.service.orderParts.OrderPartsService;
import com.cf.imes.module.executor.service.ordercomponent.OrderComponentService;
import com.cf.imes.module.executor.service.orderitem.OrderItemService;
import com.cf.imes.module.executor.service.plate.PlateService;
import org.springframework.aop.framework.AopContext;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.validation.annotation.Validated;

import jakarta.annotation.Resource;

import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Optional;
import java.util.Set;
import java.util.stream.Collectors;

import static com.cf.imes.framework.common.util.string.SearchUtil.insertSeparator;
import static com.cf.imes.framework.security.core.util.SecurityFrameworkUtils.getUserOrganId;
import static com.cf.imes.module.executor.enums.ErrorCodeConstants.NO_PRODUCTION_ORDER_INFORMATION_AVAILABLE;
import static com.cf.imes.module.executor.enums.ErrorCodeConstants.ORDER_ALREADY_PACKAGED;
import static com.cf.imes.module.executor.enums.ErrorCodeConstants.ORDER_NOT_EXISTS;
import static com.cf.imes.module.executor.enums.ErrorCodeConstants.ORDER_PACK_DATA_NULL_ERROR;
import static com.cf.imes.module.executor.enums.ErrorCodeConstants.ORDER_PARTS_NOT_EXISTS;
import static com.cf.imes.module.executor.enums.ErrorCodeConstants.PACK_DATA_NULL;
import static com.cf.imes.module.executor.enums.ErrorCodeConstants.PARTS_PACK_ITEM_SOURCE_NOT_EXISTS;
import static com.cf.imes.module.executor.enums.ErrorCodeConstants.PARTS_PACK_NUM_NOT_ENOUGH;
import static com.cf.imes.module.executor.enums.ErrorCodeConstants.PLATE_NOT_EXISTS;


@Service
@Validated
public class PackServiceImpl implements PackService {

    @Resource
    private OrderPackageMapper orderPackageMapper;

    @Resource
    private OrderItemMapper orderItemMapper;

    @Resource
    private OrderPartsMapper orderPartsMapper;

    @Resource
    private PlateMapper orderPlateMapper;

    @Resource
    private OrderMapper ordersMapper;

    @Resource
    private SnowflakeIdWorker3rd idWorker;

    @Resource
    private OrderPlanApi orderPlanApi;

    @Resource
    private OrderService orderService;

    @Resource
    private PlateService plateService;

    @Resource
    private OrderPartsService orderPartsService;

    @Resource
    private OrderItemService orderItemService;

    @Resource
    private OrderComponentService orderComponentService;

    @Resource
    private OrderInfoVersionControlService orderInfoVersionControlService;

    // 打包分页查询
    @Override
    public PageResult<PackRespVO> getPackPage(PackPageReqVO pageReqVO) {

        PageDTO<PackRespVO> page = new PageDTO<>(pageReqVO.getPageNo(), pageReqVO.getPageSize());

        List<Long> orderIds = new ArrayList<>();


        if (pageReqVO.getIsUp() != null) {

            return handleIsUpCase(pageReqVO, orderIds,pageReqVO.getIsUp());

        } else {

            return handleNormalCase(pageReqVO, orderIds, page);

        }


    }

    @Override
    public List<OrderPackageVO> getOrderPack(PackageDetailsReqVO reqVO) {
        List<Long> orderIds = reqVO.getOrderIds();

        List<OrderPackageVO> orderPackageVOS = orderPackageMapper.getPackageNoInOrderIds(orderIds);

        if (orderPackageVOS.isEmpty()) {
            return new ArrayList<>();
        }

        return orderPackageVOS;

    }


    @Override
    public PageResult<OrderPackageVO> getPageOrderPack(PackageDetailsReqVO reqVO) {

        PageDTO<OrderPackagDO> page = new PageDTO<>(reqVO.getPageNo(), reqVO.getPageSize());

        Long orderId = Long.valueOf(reqVO.getOrderId());

        IPage<OrderPackagDO> orderPackagDOs = orderPackageMapper.selectPage(page, new LambdaQueryWrapperX<OrderPackagDO>()
                .eq(OrderPackagDO::getOrderId, orderId)
                .likeIfPresent(OrderPackagDO::getPackageNo, reqVO.getPackageNo())
                .eqIfPresent(OrderPackagDO::getStatus, reqVO.getPackStatus())
                .orderByDesc(OrderPackagDO::getCreateTime)
        );

        List<OrderPackagDO> records = orderPackagDOs.getRecords();
        if (CollUtil.isEmpty(records)) {
            return new PageResult<>();
        }


        return new PageResult<>(BeanUtil.copyToList(records, OrderPackageVO.class), orderPackagDOs.getTotal());

    }




    // 拆包
    @Override
    @Transactional(rollbackFor = Exception.class)
    public OrderPackRespVO unpacking(Long packageID) {

        List<OrderPackagDO> orderPackagDOs = orderPackageMapper.selectList(new LambdaQueryWrapper<OrderPackagDO>()
                .eq(OrderPackagDO::getPackageNo, packageID)
        );
        AssertUtils.notEmpty(orderPackagDOs, ORDER_PACK_DATA_NULL_ERROR);

        // 整理出orderIds
        List<Long> orderIds = orderPackagDOs.stream().map(OrderPackagDO::getOrderId).distinct().toList();

        // 更新包裹状态
        orderPackageMapper.update(new LambdaUpdateWrapper<OrderPackagDO>()
                .eq(OrderPackagDO::getPackageNo, packageID)
                .in(OrderPackagDO::getOrderId, orderIds)
                .set(OrderPackagDO::getStatus, OrderPackageStatusEnum.UNPACKED.getStatus())
        );

        for (Long orderId : orderIds) {
            OrderDO orderDO = ordersMapper.selectById(orderId);
            orderDO.setPackaged(OrderPackageStatusEnum.UNPACKED.getStatus());
            if (orderDO.getStatus().equals(OrderStatusEnum.FINISH_PRODUCTION.getStatus())) {
                orderDO.setStatus(OrderStatusEnum.IN_PRODUCTION.getStatus());
                orderDO.setFinishTime(null);
            }
            ordersMapper.updateById(orderDO);
        }
        return typeConversion(orderPackagDOs.get(0), orderIds);
    }


    @Override
    @Transactional(rollbackFor = Exception.class)
    public OrderPackRespVO updatePack(OrderPackReqVO packageVO) {
        Long organId = getUserOrganId();
        String packNo = packageVO.getPackNo();
        List<Long> orderIds = packageVO.getOrderIds();
        List<Long> currentOrderIds = packageVO.getCurrentOrderIds();
        List<Long> addPlateNos = packageVO.getAddPlateNoList();
        List<Long> deletePlateNos = packageVO.getDeletePlateNoList();
        List<PackagePartsSaveReqVO> addPartsList = packageVO.getAddPartsList();
        List<PackagePartsSaveReqVO> delPartsList = packageVO.getDelPartsList();
        Integer packMethod = packageVO.getPackMethod();

        List<OrderPackagDO> existPackageDO = validateOrdersExists(orderIds, packNo);

        // 新增/删除 板件配件全为空代表是原封不动的封包
        boolean justPack = CollUtil.isEmpty(addPlateNos) && CollUtil.isEmpty(addPartsList)
                && CollUtil.isEmpty(deletePlateNos) && CollUtil.isEmpty(delPartsList);

        // 判断包裹ID是否为空，为空，走新增，不为空，走更新
        if (CollUtil.isEmpty(existPackageDO)) {
            if (justPack) {
                throw new ServiceException(PACK_DATA_NULL);
            }

            String packageNo = generatePackageNo();
            List<OrderPackagDO> orderPackageDOS = new ArrayList<>();
            for (Long orderId : currentOrderIds) {
                OrderPackagDO orderPackageDO = new OrderPackagDO();
                orderPackageDO.setOrderId(orderId);
                orderPackageDO.setPackageNo(packageNo);
                orderPackageDO.setStatus((OrderPackageStatusEnum.PACKAGED.getStatus()));
                orderPackageDO.setRemark(packageVO.getRemark());
                orderPackageDO.setOrganId(organId);
                orderPackageDOS.add(orderPackageDO);
            }
            orderPackageMapper.insertBatch(orderPackageDOS);
            // 板件明细新增包裹 ID
            List<List<Long>> split = CollUtil.split(addPlateNos, 1000);
            if (CollUtil.isNotEmpty(split)) {
                for (List<Long> batch : split) {
                    List<Long> plateIds = orderPlateMapper.selectList(new LambdaQueryWrapper<PlateDO>()
                            .in(PlateDO::getPlateNo, batch)
                            .in(PlateDO::getOrderId, currentOrderIds)
                            .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, currentOrderIds)
                            .in(OrderItemDO::getPlateId, plateIds)
                            .eq(OrderItemDO::getPackageId, 0L)
                            .set(OrderItemDO::getPackageId, packageNo)
                    );
                }
            }

            // 配件明细新增包裹 ID
            processParts(addPartsList, packMethod, currentOrderIds, packageNo, true);

            // 更新订单打包状态
            List<OrderDO> orderDOS = ordersMapper.selectBatchIds(currentOrderIds);
            for (OrderDO orderDO : orderDOS) {
                if (validateOrderPack(orderDO.getId())) {

                    // 修改订单的打包状态
                    PackServiceImpl p = (PackServiceImpl) AopContext.currentProxy();
                    p.updateOrderStatus(orderDO);
                }
            }
            // 更新已打包数量到订单
            orderInfoVersionControlService.updateOrderPackNum(orderDOS);

            return typeConversion(orderPackageDOS.get(0), currentOrderIds);
        }

        // 从包裹对应订单列表 和 现在还有的订单列表做对比，算出差集，对应列表有当前没有就是要删，对应列表没有当前有就是要新增
        Set<Long> existOrderIdSet = existPackageDO.stream()
                .map(OrderPackagDO::getOrderId)
                .collect(Collectors.toSet());

        Set<Long> currentOrderIdSet = new HashSet<>(currentOrderIds);
        // 删除：exist - current
        List<Long> toDelete = existOrderIdSet.stream()
                .filter(id -> !currentOrderIdSet.contains(id))
                .collect(Collectors.toList());

        // 新增：current - exist
        List<Long> toAdd = currentOrderIdSet.stream()
                .filter(id -> !existOrderIdSet.contains(id))
                .collect(Collectors.toList());


        String existPackageNo = existPackageDO.get(0).getPackageNo();
        // 板件明细新增包裹 ID
        List<List<Long>> split = CollUtil.split(addPlateNos, 1000);
        if (CollUtil.isNotEmpty(split)) {
            for (List<Long> batch : split) {
                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::getPackageId, 0L)
                        .set(OrderItemDO::getPackageId, existPackageNo)
                );
            }
        }

        // 板件明细移除包裹 ID
        List<List<Long>> split3 = CollUtil.split(deletePlateNos, 1000);
        if (CollUtil.isNotEmpty(split3)) {
            for (List<Long> batch : split3) {
                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::getPackageId, existPackageNo)
                        .set(OrderItemDO::getPackageId, 0L)
                );
            }
        }

        // 配件明细移除包裹 ID
        processParts(delPartsList, packMethod, orderIds, existPackageNo, false);

        // 配件明细新增包裹 ID
        processParts(addPartsList, packMethod, orderIds, existPackageNo, true);

        // 更新封包状态
        orderPackageMapper.update(new LambdaUpdateWrapper<OrderPackagDO>()
                .eq(OrderPackagDO::getPackageNo, existPackageNo)
                .in(OrderPackagDO::getOrderId, orderIds)
                .eq(OrderPackagDO::getStatus, OrderPackageStatusEnum.UNPACKED.getStatus())
                .set(OrderPackagDO::getStatus, OrderPackageStatusEnum.PACKAGED.getStatus()));

        // 删除没有订单组成的包裹
        orderPackageMapper.delete(new LambdaQueryWrapper<OrderPackagDO>()
                .eq(OrderPackagDO::getPackageNo, existPackageNo)
                .in(OrderPackagDO::getOrderId, toDelete)
        );

        // 新增新订单组成的包裹
        List<OrderPackagDO> addOrderPackageDOS = new ArrayList<>();
        for (Long addOrderId : toAdd) {
            OrderPackagDO orderPackageDO = new OrderPackagDO();
            orderPackageDO.setOrderId(addOrderId);
            orderPackageDO.setPackageNo(existPackageNo);
            orderPackageDO.setStatus((OrderPackageStatusEnum.PACKAGED.getStatus()));
            orderPackageDO.setRemark(packageVO.getRemark());
            orderPackageDO.setOrganId(organId);
            addOrderPackageDOS.add(orderPackageDO);
        }
        orderPackageMapper.insertBatch(addOrderPackageDOS);

        // 更新订单打包状态
        List<OrderDO> orderDOS = ordersMapper.selectBatchIds(orderIds);
        for (OrderDO orderDO : orderDOS) {
            if (validateOrderPack(orderDO.getId())) {

                // 修改订单的打包状态
                PackServiceImpl p = (PackServiceImpl) AopContext.currentProxy();
                p.updateOrderStatus(orderDO);
            }
        }
        if (!justPack) {
            // 更新已打包数量到订单
            orderInfoVersionControlService.updateOrderPackNum(orderDOS);
        }

        return typeConversion(existPackageDO.get(0), orderIds);

    }

    /**
     * 分组规则
     * @param item
     * @param packMethod
     * @return
     */
    private String getGroupKey(PackagePartsSaveReqVO item, Integer packMethod) {
        if (ObjectUtil.equals(OrderPackageMethodEnum.ROOM_NAME.getMethod(), packMethod)) {
            return item.getRoomId() + "-" + item.getBodyId();
        } else if (ObjectUtil.equals(OrderPackageMethodEnum.BODY_NAME.getMethod(), packMethod)) {
            return String.valueOf(item.getBodyId());
        } else if (ObjectUtil.equals(OrderPackageMethodEnum.ORDER.getMethod(), packMethod)) {
            return String.valueOf(item.getOrderId());
        }
        // todo 规范异常
        throw new IllegalArgumentException("未知打包方式: " + packMethod);
    }

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

        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 (isAdd) {
            // 新增要查的是没打包的
            wrapper.eq(OrderItemDO::getPackageId, 0L);
        } else {
            // 删除看的是已打包的
            wrapper.eq(OrderItemDO::getPackageId, packageNo);
        }

        if (ObjectUtil.equals(OrderPackageMethodEnum.ROOM_NAME.getMethod(), packMethod)) {
            String[] keys = groupKey.split("-");
            wrapper.eq(OrderItemDO::getRoomId, keys[0])
                    .eq(OrderItemDO::getBodyId, keys[1])
                    .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;
    }

    /**
     * 配件打包数量处理
     *
     * @param partsList
     * @param packMethod
     * @param orderIds
     * @param packageId
     * @param isAdd
     */
    private void processParts(List<PackagePartsSaveReqVO> partsList,
                              Integer packMethod,
                              List<Long> orderIds,
                              String packageId,
                              boolean isAdd) {

        if (CollUtil.isEmpty(partsList)) return;

        // 分组
        Map<String, List<PackagePartsSaveReqVO>> groupMap =
                partsList.stream().collect(Collectors.groupingBy(item -> getGroupKey(item, packMethod)));

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

            String groupKey = entry.getKey();

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

                LambdaQueryWrapper<OrderItemDO> wrapper =
                        buildWrapper(groupKey, vo.getPartsId(), packMethod, orderIds, packageId, isAdd);

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

                if (isAdd) {
                    // 分配打包数量
                    allocateGroup(list, packageId, vo.getNum());
                } else {
                    // 还原打包数量
                    restoreGroup(list);
                }
            }
        }
    }

    /**
     * 还原配件打包数量
     *
     * @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_PACK_ITEM_SOURCE_NOT_EXISTS));

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

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

            if (CollUtil.isNotEmpty(subItems)) {
                // 有子
                if (ObjectUtil.notEqual(parent.getPackageId(), 0L)) {
                    // 父本身已打包，则降级成子
                    parent.setSourceId(parent.getId());
                    updateList.add(parent);

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

                    newBase.setId(null);
                    newBase.setSourceId(0L);
                    newBase.setPackNum(parent.getNum() - subTotal);
                    newBase.setPackageId(0L);
                    insertList.add(newBase);

                } else {
                    // 本身没打包，把父-子packNum扣掉
                    parent.setPackNum(parentPack - subTotal);
                    updateList.add(parent);
                }

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

            } else {
                // 没有子，打包了就还原数
                if (ObjectUtil.notEqual(parent.getPackageId(), 0L)) {
                    parent.setPackNum(0.0);
                    parent.setPackageId(0L);
                    updateList.add(parent);
                }
            }
        }

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

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

        int remain = targetNum;

        for (OrderItemDO item : list) {

            if (remain <= 0) {
                break;
            }

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

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

                // 标记打包
                item.setPackageId(Long.parseLong(packNo));

                // 更新打包数量
                item.setPackNum(current);

                orderItemMapper.updateById(item);

                remain -= current;
            }

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

                // 原记录累加打包数量
                item.setPackNum(item.getPackNum() + remain);
                orderItemMapper.updateById(item);

                // 新建打包记录
                OrderItemDO newItem = buildPackItem(item, packNo, remain);
                orderItemMapper.insert(newItem);

                remain = 0;
                break;
            }
        }

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

    /**
     * 打包未全覆盖创建item副本
     *
     * @param source
     * @param packNo
     * @param packNum
     * @return
     */
    private OrderItemDO buildPackItem(OrderItemDO source, String packNo, double packNum) {
        OrderItemDO newItem = new OrderItemDO();

        // 基础字段复制（建议用BeanUtils）
        BeanUtils.copyProperties(source, newItem);

        newItem.setId(null); // 新ID
        newItem.setPackNum(packNum);

        // 标记为“已打包”
        newItem.setPackageId(Long.parseLong(packNo));
        newItem.setSourceId(source.getId());

        return newItem;
    }


    // 判断当前订单的板材和配件是否已全部打包且当前订单的包裹已全部封包
    public Boolean validateOrderPack(Long orderId) {

        List<OrderPackagDO> orderPackageDOS = orderPackageMapper.selectPackList(orderId, getUserOrganId());

        if (!orderPackageDOS.isEmpty()) {
            return false;
        }

        List<PlateAndPartIdList> partsIds = orderItemMapper.selectOrderPackPartsIds(orderId, getUserOrganId());

        List<PlateAndPartIdList> plateIds = orderItemMapper.selectOrderPackPlateIds(orderId, getUserOrganId());

        return partsIds.isEmpty() && plateIds.isEmpty();

    }


    // 修改当前订单的工序状态和订单的状态
    @Transactional(rollbackFor = Exception.class)
    public OrderDO updateOrderStatus(OrderDO orderDO) {
        Long orderId = orderDO.getId();

        // 修改订单的打包状态为已打包
        orderDO.setPackaged(OrderPackageStatusEnum.PACKAGED.getStatus());


        if(orderPlanApi.getOrder(orderId).getData()){
            orderDO.setStatus(OrderStatusEnum.FINISH_PRODUCTION.getStatus());
            orderDO.setFinishTime(LocalDateTime.now());
        }


        ordersMapper.updateById(orderDO);

        return orderDO;
    }


    // 查询包裹
    @Override
    public List<OrderPackRespVO> selectPack(Long orderId) {

        List<OrderPackagDO> orderPackageDOS = orderPackageMapper.selectPackStatus(orderId, getUserOrganId());

        return orderPackageDOS.stream().map(this::typeConversion).toList();

    }



    @Override
    @Transactional(rollbackFor = Exception.class)
    public void deleteOrderPack(PackReqVO reqVO) {
        Long packageNo = reqVO.getPackageNo();
        List<Long> orderIds = reqVO.getOrderIds();

        List<OrderDO> orderDOS = ordersMapper.selectBatchIds(orderIds);

        List<OrderPackagDO> orderPackagDOS = orderPackageMapper.selectList(new LambdaQueryWrapper<OrderPackagDO>()
                .eq(OrderPackagDO::getPackageNo, packageNo)
                .in(OrderPackagDO::getOrderId, orderIds)
        );
        if (CollUtil.isEmpty(orderPackagDOS)) {
            return;
        }

        // 如果有未拆包的提示先拆包
        if (orderPackagDOS.stream().anyMatch(o -> ObjectUtil.equals(OrderPackageStatusEnum.PACKAGED.getStatus(), o.getStatus()))) {
            throw new ServiceException(ORDER_ALREADY_PACKAGED);
        }
        // 整理出该包裹对应的订单id列表
        List<Long> packOrderIds = orderPackagDOS.stream()
                .map(OrderPackagDO::getOrderId)
                .distinct()
                .toList();

        // 移除板件的打包状态
        orderItemMapper.update(new LambdaUpdateWrapper<OrderItemDO>()
                .in(OrderItemDO::getOrderId, packOrderIds)
                .eq(OrderItemDO::getPackageId, packageNo)
                .eq(OrderItemDO::getPartsId, 0)
                .set(OrderItemDO::getPackageId, 0)
        );

        // 查询是否有部分打包的配件
        List<OrderItemDO> newItemDOS = orderItemMapper.selectList(new LambdaQueryWrapper<OrderItemDO>()
                .in(OrderItemDO::getOrderId, packOrderIds)
                .eq(OrderItemDO::getPackageId, packageNo)
                .ne(OrderItemDO::getPartsId, 0)
                .ne(OrderItemDO::getSourceId, 0)
        );
        // 整理出存在部分打包的配件partsId
        List<Long> partsIds = newItemDOS.stream()
                .map(OrderItemDO::getPartsId)
                .distinct()
                .toList();

        if (CollUtil.isNotEmpty(partsIds)) {
            // 查询partIds下的item列表
            List<OrderItemDO> partItemDOS = orderItemMapper.selectList(new LambdaQueryWrapper<OrderItemDO>()
                    .in(OrderItemDO::getOrderId, packOrderIds)
                    .in(OrderItemDO::getPartsId, partsIds)
            );
            // 基于order_parts id分组
            Map<Long, List<OrderItemDO>> partItemMap = newItemDOS.stream().collect(Collectors.groupingBy(OrderItemDO::getSourceId));

            List<OrderItemDO> updateList = new ArrayList<>();
            List<Long> deleteIds = new ArrayList<>();
            List<OrderItemDO> insertList = new ArrayList<>();
            for (Map.Entry<Long, List<OrderItemDO>> entry : partItemMap.entrySet()) {

                List<OrderItemDO> list = entry.getValue();
                if (CollUtil.isEmpty(list)) {
                    continue;
                }

                // 1、找基准 item（source = true）
                OrderItemDO baseItem = partItemDOS.stream()
                        .filter(i -> ObjectUtil.equals(entry.getKey(), i.getId()))
                        .findFirst()
                        .orElseThrow(() -> new ServiceException(
                                new ErrorCode(10001, "未找到 sourceId对应的基准item, partsId=" + entry.getKey())
                        ));

                boolean basePacked = baseItem.getPackageId() != null && baseItem.getPackageId() != 0;
                double basePack = Optional.ofNullable(baseItem.getPackNum()).orElse(0.0);
                double sumOthers = 0.0;

                // 2、累加其他 item
                for (OrderItemDO item : list) {

                    if (item.getId().equals(baseItem.getId())) continue;

                    sumOthers += Optional.ofNullable(item.getPackNum()).orElse(0.0);
                    deleteIds.add(item.getId());
                }

                // 情况1：未打包 → 正常合并
                if (!basePacked) {
                    baseItem.setPackNum(basePack - sumOthers);
                    updateList.add(baseItem);
                }
                // 情况2：已打包 → 拆分新基准
                else {
                    // ① 原基准降级
                    baseItem.setSourceId(baseItem.getId());
                    updateList.add(baseItem);

                    // ② 新建基准
                    OrderItemDO newBase = new OrderItemDO();
                    BeanUtil.copyProperties(baseItem, newBase);

                    newBase.setId(null);
                    newBase.setSourceId(0L);
                    newBase.setPackageId(0L); // 新基准一定是未打包
                    newBase.setPackNum(baseItem.getNum() - sumOthers);

                    insertList.add(newBase);
                }
            }

            // 批量执行
            if (!updateList.isEmpty()) {
                orderItemMapper.updateBatch(updateList);
            }

            if (!insertList.isEmpty()) {
                orderItemMapper.insertBatch(insertList);
            }

            if (!deleteIds.isEmpty()) {
                orderItemMapper.deleteByIds(deleteIds);
            }
        }
        // 移除配件的打包状态
        orderItemMapper.update(new LambdaUpdateWrapper<OrderItemDO>()
                .in(OrderItemDO::getOrderId, packOrderIds)
                .eq(OrderItemDO::getPackageId, packageNo)
                .eq(OrderItemDO::getPlateId, 0)
                .set(OrderItemDO::getPackageId, 0)
                .set(OrderItemDO::getPackNum, 0)
        );


        // 移除包裹关联数据
        orderPackageMapper.delete(new LambdaQueryWrapper<OrderPackagDO>()
                .eq(OrderPackagDO::getPackageNo, packageNo)
                .in(OrderPackagDO::getOrderId, packOrderIds)
        );

        // 更新订单的已打包状态
        ordersMapper.update(new LambdaUpdateWrapper<OrderDO>()
                .in(OrderDO::getId, packOrderIds)
                .eq(OrderDO::getPackaged, OrderPackageStatusEnum.PACKAGED.getStatus())
                .set(OrderDO::getPackaged, OrderPackageStatusEnum.UNPACKED.getStatus())
        );

        // 更新已打包数量到订单
        orderInfoVersionControlService.updateOrderPackNum(orderDOS);
    }

    // 生成包裹编号
    private String generatePackageNo() {

        long packNo = idWorker.nextId();
        long obtainingTime = SnowflakeIdWorker3rd.obtainingTime();

        return (obtainingTime) + Long.toString(packNo).substring(2);

    }

    /**
     * 校验包裹有效性
     *
     * @param orderIds
     * @param packNo
     */
    private List<OrderPackagDO> validateOrdersExists(List<Long> orderIds, String packNo) {

        List<OrderDO> orderDO = ordersMapper.selectByIds(orderIds);
        AssertUtils.notEmpty(orderDO, ORDER_NOT_EXISTS);

        if (CharSequenceUtil.isNotEmpty(packNo)) {
            List<OrderPackagDO> orderPackageDOS = orderPackageMapper.selectList(new LambdaQueryWrapper<OrderPackagDO>()
                    .eq(OrderPackagDO::getPackageNo, packNo));
            AssertUtils.notEmpty(orderPackageDOS, ORDER_PACK_DATA_NULL_ERROR);
            return orderPackageDOS;
        }

        return null;
    }

    // 类型转换
    private OrderPackRespVO typeConversion(OrderPackagDO orderPackageDO) {
        return OrderPackRespVO.builder()
                .orderId(orderPackageDO.getOrderId())
                .organId(orderPackageDO.getOrganId())
                .packageNo(orderPackageDO.getPackageNo())
                .name(orderPackageDO.getName())
                .status(orderPackageDO.getStatus())
                .remark(orderPackageDO.getRemark())
                .build();

    }

    private OrderPackRespVO typeConversion(OrderPackagDO orderPackageDO, List<Long> orderIds) {
        return OrderPackRespVO.builder()
                .orderIds(orderIds)
                .organId(orderPackageDO.getOrganId())
                .packageNo(orderPackageDO.getPackageNo())
                .name(orderPackageDO.getName())
                .status(orderPackageDO.getStatus())
                .remark(orderPackageDO.getRemark())
                .build();

    }




    // 打包翻页查询
    private PageResult<PackRespVO> handleIsUpCase(PackPageReqVO pageReqVO, List<Long> orderIds,Boolean isUp) {

        IPage<PackRespVO> packRespVOS = new PageDTO<>();

        OrderDO order = ordersMapper.selectById(pageReqVO.getOrderId());
        AssertUtils.notEmpty(order, ORDER_NOT_EXISTS);

        List<PackRespVO> packRespVOList = Boolean.TRUE.equals(isUp) ?
                ordersMapper.selectOrderIdsTrue(order.getCreateTime().toString(), getUserOrganId(), order.getId()) :
                ordersMapper.selectOrderIdsFalse(order.getCreateTime().toString(), getUserOrganId(), order.getId());

        if (packRespVOList.isEmpty()) {
            throw new ServiceException(NO_PRODUCTION_ORDER_INFORMATION_AVAILABLE, Boolean.TRUE.equals(isUp) ? "第" : "最后");
        }
        packRespVOS.setRecords(packRespVOList);

        packRespVOS.setTotal(1);

        orderIds.addAll(packRespVOS.getRecords().stream().map(PackRespVO::getId).toList());

        return buildPageResult(orderIds,packRespVOS);
    }



    // 打包分页查询
    private PageResult<PackRespVO> handleNormalCase(PackPageReqVO pageReqVO, List<Long> orderIds, PageDTO<PackRespVO> page) {

        pageReqVO.setCustomer(insertSeparator(pageReqVO.getCustomer()));
        pageReqVO.setCustomOrderNo(insertSeparator(pageReqVO.getCustomOrderNo()));
        pageReqVO.setAddress(insertSeparator(pageReqVO.getAddress()));


        // 查询主单分页
        IPage<PackRespVO> packRespVOS = ordersMapper.selectPackOrderList(page, pageReqVO, getUserOrganId());

        if (CollUtil.isEmpty(packRespVOS.getRecords())) {
            return new PageResult<>();
        }

        orderIds.addAll(packRespVOS.getRecords().stream().map(PackRespVO::getId).toList());

        // 查询分页下子级
        List<PackRespVO> childList = ordersMapper.selectPackOrderChildList(pageReqVO, orderIds, getUserOrganId());

        if (CollUtil.isNotEmpty(childList)) {
            for (PackRespVO childPackRespVO : childList) {
                packRespVOS.getRecords().add(childPackRespVO);
                orderIds.add(childPackRespVO.getId());
            }
        }

        PageResult<PackRespVO> packRespVOPageResult = buildPageResult(orderIds, packRespVOS);
        return new PageResult<>(packRespVOPageResult.getList(), packRespVOS.getTotal());

    }

    /**
     * 分页数据查询对应的板件总数、包裹数量、已打包板件数量
     *
     * @param orderIds
     * @param packRespVOS
     * @return
     */
    private PageResult<PackRespVO> buildPageResult(List<Long> orderIds, IPage<PackRespVO> packRespVOS) {

        if (orderIds.isEmpty()) {
            return new PageResult<>();
        }
        List<PackRespVO> records = packRespVOS.getRecords();

        // 查询当前生产的包裹数量
        List<PackRespVO> orderPackNumGroup = orderPackageMapper.selectPackPage(orderIds, getUserOrganId());

        for (PackRespVO vosRecord : records) {
            // 已打包裹数
            vosRecord.setPackCount(orderPackNumGroup.stream().filter(f -> Objects.equals(f.getId(), vosRecord.getId())).mapToInt(PackRespVO::getPackCount).sum());

        }

        Map<Long, PackRespVO> parentMap = new HashMap<>();
        List<PackRespVO> result = new ArrayList<>();

        // 1. 把所有 parent 放进 map
        for (PackRespVO vo : records) {
            if (vo.getParentId() == 0) {
                vo.setChild(new ArrayList<>());
                parentMap.put(vo.getId(), vo);
                result.add(vo);
            }
        }

        // 2. 再挂子节点
        for (PackRespVO vo : records) {
            if (vo.getParentId() != 0) {
                PackRespVO parent = parentMap.get(vo.getParentId());
                if (parent != null) {
                    parent.getChild().add(vo);
                }
            }
        }
        return new PageResult<>(result, Long.valueOf(result.size()));

    }

    @Override
    public List<String> getComponentCorrelation(PackScanComponentCorrelationReqVO reqVO) {
        // 进来是板用的是板编号，配件用的是配件id
        String id = reqVO.getId();
        Integer itemType = reqVO.getItemType();
        Integer type = reqVO.getType();
        List<Long> orderIds = reqVO.getOrderIds();
        // 没有归属部件返回自己本身
        List<String> self = List.of(id);

        List<OrderItemDO> itemDOS;
        if (com.cf.imes.module.executor.enums.OrderItemTypeEnum.PLATE_ITEM.getStatus().equals(itemType)) {
            // 板件
            PlateDO plate = plateService.getPlateByNo(id, ArrayUtil.toArray(orderIds, Long.class));
            AssertUtils.notEmpty(plate, PLATE_NOT_EXISTS);
            // 查询关联部件id
            itemDOS = orderItemService.getPlateItemCompId(plate.getOrderId(), plate.getId());
        } else {
            Long partsId = Long.valueOf(id);
            // 配件
            OrderPartsDO part = orderPartsService.getPart(partsId);
            AssertUtils.notEmpty(part, ORDER_PARTS_NOT_EXISTS);
            // 查询关联部件id
            itemDOS = orderItemService.getPartItemCompId(partsId);
        }

        if (ObjectUtil.isEmpty(itemDOS)) {
            // 没查到返回自己本身
            return self;
        }

        List<Long> componentIdList;
        Long compId = itemDOS.get(0).getCompId();
        // 需要关联加工组时，记录所有groupId不为空和0的记录
        List<Long> groupIds = reqVO.isRelateGroup() ?
                itemDOS.stream().filter(Objects::nonNull).map(OrderItemDO::getGroupId).filter(f -> ObjectUtil.isNotNull(f) && f != 0).distinct().toList() : null;
        if (PackScanComponentCorrelationTypeEnum.SELF.getType().equals(type)) {
            // 本身不查部件树
            componentIdList = null;
        } else if (PackScanComponentCorrelationTypeEnum.PARENT.getType().equals(type)) {
            // 部件父级
            componentIdList = orderComponentService.getChildComponentIdsOnMy(compId);
        } else {
            // 部件顶级
            componentIdList = orderComponentService.getChildComponentIdsOnTopId(compId);
        }

        // 没有归属部件且没有归属加工组返回自己本身
        if (CollUtil.isEmpty(componentIdList) && CollUtil.isEmpty(groupIds)) {
            return self;
        }

        // 是否勾选了加工组
        List<String> componentIdsCorrelationItemIds = orderItemService.getComponentIdsCorrelationItemIds(orderIds, componentIdList, groupIds);
        if (CollUtil.isEmpty(componentIdsCorrelationItemIds)) {
            return self;
        }

        return componentIdsCorrelationItemIds;
    }

    @Override
    public OrdersUnpackDetailRespVO getOrdersUnpackDetails(List<Long> orderIds) {
        OrdersUnpackDetailRespVO ordersUnpackDetailRespVO = new OrdersUnpackDetailRespVO();
        // 查询多订单信息
        ordersUnpackDetailRespVO.setOrders(orderService.getPackOrdersInfo(orderIds));
        // 查询板件
        List<PlateDetailsRespVO> plates = orderPlateMapper.selectOrdersPackPlateList(orderIds);
        // 查询配件
        List<OrderPartsRespVO> parts = orderPartsMapper.selectOrdersPartsList(orderIds);

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

    /**
     * 板件分组：加工组
     *
     * @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() != null
                    && vo.getMultiNum() > 1
                    && vo.getMultiSort() != null
                    && vo.getCabinetName() != null) {

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

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

                BeanUtils.copyProperties(row, newVo);

                // ===== 初始化 =====
                newVo.setProcessGroupNameList(new ArrayList<>());
                newVo.setComponentNameList(new ArrayList<>());
                newVo.setNum(BigDecimal.ZERO);

                return newVo;
            });

            // ===== 2. 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()));
            }

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

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

        Collection<OrderPartsRespVO> values = map.values();
        for (OrderPartsRespVO vo : values) {

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

            // ===== 部件组拼接 =====
            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 values;
    }

    @Override
    public List<PackageDetailsRespVO> getOrdersPackageDetails(PackageDetailReqVO reqVO) {
        Set<Long> orderIds = reqVO.getOrderIds().stream().collect(Collectors.toSet());
        String packageNo = reqVO.getPackageNo();
        List<OrderPackagDO> orderPackagDONews = orderPackageMapper.selectList(new LambdaQueryWrapper<OrderPackagDO>()
                .in(OrderPackagDO::getOrderId, orderIds)
                .eq(OrderPackagDO::getPackageNo, packageNo));

        if (CollUtil.isEmpty(orderPackagDONews)) {
            return new ArrayList<>();
        }
        // 查询板件
        List<PackageDetailsRespVO> packPlateList = orderPlateMapper.selectPackedPlateList(orderIds, packageNo);
        // 查询配件
        List<PackageDetailsRespVO> packPartsList = orderPartsMapper.selectPackedParts(orderIds, packageNo);

        Collection<PackageDetailsRespVO> resultList = buildPackPlateGroup(packPlateList);
        resultList.addAll(buildPackPartsGroup(orderIds, packPartsList));
        return CollUtil.newArrayList(resultList);
    }

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

        for (PackageDetailsRespVO row : plates) {

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

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

                BeanUtils.copyProperties(row, newVo);

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

                return newVo;
            });

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

        Collection<PackageDetailsRespVO> values = map.values();
        // ===== 3. 转换成逗号字符串 =====
        for (PackageDetailsRespVO 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 new ArrayList<>(values);
    }

    /**
     * 包裹配件分组：加工组、部件（目前是一对一）
     *
     * @param parts
     * @return
     */
    private Collection<PackageDetailsRespVO> buildPackPartsGroup(Set<Long> orderIds, List<PackageDetailsRespVO> parts) {
        if (CollUtil.isEmpty(parts)) {
            return Collections.emptyList();
        }

        // 提取当前包裹涉及的配件
        Set<Long> partsIds = parts.stream()
                .map(PackageDetailsRespVO::getPartsId)
                .collect(Collectors.toSet());

        // 查询加工组/组件关系
        List<PackageDetailsRespVO> relations =
                orderPartsMapper.selectPackedPartsGroupAndComponent(orderIds, partsIds);
        Map<String, List<PackageDetailsRespVO>> relationMap =
                relations.stream()
                        .collect(Collectors.groupingBy(item ->
                                item.getPartsId()
                                        + "_" + item.getRoomId()
                                        + "_" + item.getBodyId()
                        ));

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

        for (PackageDetailsRespVO row : parts) {

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

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

                BeanUtils.copyProperties(row, newVo);

                // ===== 初始化 =====
                newVo.setPackNum(BigDecimal.ZERO);

                return newVo;
            });

            // ===== 2. num 累加 =====
            if (row.getPackNum() != null) {
                vo.setPackNum(vo.getPackNum().add(row.getPackNum()));
            }
        }

        Collection<PackageDetailsRespVO> values = map.values();

        for (PackageDetailsRespVO vo : values) {

            String key = vo.getPartsId()
                    + "_" + vo.getRoomId()
                    + "_" + vo.getBodyId();

            List<PackageDetailsRespVO> relationList = relationMap.get(key);

            if (CollUtil.isNotEmpty(relationList)) {

                String processGroup = relationList.stream()
                        .map(PackageDetailsRespVO::getProcessGroup)
                        .filter(StrUtil::isNotBlank)
                        .collect(Collectors.joining(","));

                vo.setProcessGroup(StrUtil.blankToDefault(processGroup, null));

                String componentName = relationList.stream()
                        .map(PackageDetailsRespVO::getComponentName)
                        .filter(StrUtil::isNotBlank)
                        .collect(Collectors.joining(","));

                vo.setComponentName(StrUtil.blankToDefault(componentName, null));
            }

            if (ObjectUtil.isNotNull(vo.getMultiNum())
                    && vo.getMultiNum() > 1) {

                vo.setCabinetName(
                        vo.getCabinetName() + "-" + vo.getMultiSort()
                );
            }
        }

        return values;
    }

    @Override
    public List<PackageDetailsRespVO> getOrderPackageDetails(Long orderId, String packageNo) {
        List<OrderPackagDO> orderPackagDONews = orderPackageMapper.selectList(new LambdaQueryWrapper<OrderPackagDO>()
                .eq(OrderPackagDO::getPackageNo, packageNo)
                .eq(OrderPackagDO::getOrderId, orderId)
        );

        if (CollUtil.isEmpty(orderPackagDONews)) {
            return new ArrayList<>();
        }
        Set<Long> orderIds = Set.of(orderId);
        List<PackageDetailsRespVO> packPartsList = orderPartsMapper.selectPackedParts(orderIds, packageNo);
        List<PackageDetailsRespVO> packPlateList = orderPlateMapper.selectPackedPlateList(orderIds, packageNo);

        Collection<PackageDetailsRespVO> resultList = buildPackPlateGroup(packPlateList);
        resultList.addAll(buildPackPartsGroup(orderIds, packPartsList));
        return CollUtil.newArrayList(resultList);
    }

    @Override
    public Map<String, List<Long>> getOrderIdsByPackageNo(Collection<Long> packageNo) {
        List<OrderPackagDO> orderPackagDOS = orderPackageMapper.selectList(new LambdaQueryWrapper<OrderPackagDO>()
                .in(OrderPackagDO::getPackageNo, packageNo)
                .eq(OrderPackagDO::getDeleted, DeletedCodeEnum.NOT_DELETED.getStatus())
                .select(OrderPackagDO::getPackageNo, OrderPackagDO::getOrderId)
        );
        if (CollUtil.isEmpty(orderPackagDOS)) {
            // 按照packageNo分组，value是订单列表
            return orderPackagDOS.stream()
                    .collect(Collectors.groupingBy(
                            OrderPackagDO::getPackageNo,
                            Collectors.mapping(OrderPackagDO::getOrderId, Collectors.toList())
                    ));
        }
        return Map.of();
    }

    @Override
    public void deletePackageByPackageNo(Long orderId, Set<String> packageNo) {
        orderPackageMapper.delete(new LambdaQueryWrapper<OrderPackagDO>()
                .eq(OrderPackagDO::getOrderId, orderId)
                .in(OrderPackagDO::getPackageNo, packageNo)
        );
    }
}
