package com.wms_main.service.business.serviceImpl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.wms_main.app.AppCommon;
import com.wms_main.constant.enums.mywms.OrderInCBEnums;
import com.wms_main.constant.enums.mywms.OrderOutCBEnums;
import com.wms_main.constant.enums.wms.*;
import com.wms_main.dao.*;
import com.wms_main.model.dto.request.mywms.OrderInCBReq;
import com.wms_main.model.dto.request.mywms.OrderOutCBReq;
import com.wms_main.model.dto.response.mes.MesApiResponse;
import com.wms_main.model.po.*;
import com.wms_main.repository.utils.ConvertUtils;
import com.wms_main.repository.utils.StringUtils;
import com.wms_main.repository.utils.UUIDUtils;
import com.wms_main.service.api.IExternalApiService;
import com.wms_main.service.business.IStackerTaskService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.time.LocalDateTime;
import java.util.*;
import java.util.stream.Collectors;

/**
 * 服务实现
 */
@Service
@RequiredArgsConstructor
@Slf4j
public class StackerTaskServiceImpl implements IStackerTaskService {
    /**
     * Wcs任务服务
     */
    private final ITAppWcsTaskService appWcsTaskService;
    /**
     * Wms任务服务
     */
    private final ITAppTaskService appTaskService;
    /**
     * 库位服务
     */
    private final ITAppLocationService appLocationService;
    /**
     * 载具服务
     */
    private final ITAppVehicleService appVehicleService;
    /**
     * 库存服务
     */
    private final ITAppStockService appStockService;
    /**
     * 任务记录服务
     */
    private final ITAppTaskBakService appTaskBakService;

    /**
     * 设备服务
     */
    private final ITAppEquipmentService appEquipmentService;

    private final ITAppOrderInService appOrderInService;

    private final ITAppOrderOutService appOrderOutService;

    private final IExternalApiService externalApiService;
    /**
     * 业务通用
     */
    private final AppCommon appCommon;

    /**
     * 存WcsTask表
     * 更新WmsTask表
     *
     * @param wcsTask wcs任务
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void saveWcsTaskAndUpdateWmsTask(TAppWcsTask wcsTask) {
        // 存WcsTask表
        appWcsTaskService.save(wcsTask);
        // 更新WmsTask表
        appTaskService.update(
                new LambdaUpdateWrapper<TAppTask>()
                        .set(TAppTask::getWcsTaskId, wcsTask.getWcsTaskId())
                        .set(TAppTask::getTaskStatus, WmsStackerTaskStatusEnums.EXECUTED.getCode())
                        .eq(TAppTask::getVehicleId, wcsTask.getVehicleId())
                        .eq(TAppTask::getTaskType,
                                ConvertUtils.convertStackerTaskTypeFromWcsToWms(wcsTask.getWcsTaskType()))
                        .eq(TAppTask::getTaskStatus, WmsStackerTaskStatusEnums.WAIT.getCode()));
    }

    /**
     * 实现
     *
     * @param locationFilter 申请条件
     * @return 申请到的库位，null表示无库位可用
     */
    @Override
    public TAppLocation requestOneLocation(TAppLocation locationFilter, String requestVehicleId) {
        // 目标库位
        TAppLocation targetLocation = null;
        // 设备号优先级序列
        List<Integer> equipmentIds = new ArrayList<>();

        // 判断是否传入设备号
        if (locationFilter != null && locationFilter.getEquipmentId() != null) {
            equipmentIds.add(locationFilter.getEquipmentId());
        } else {
            // 根据堆垛机任务数量，找到最空闲的那台堆垛机
            equipmentIds = findMostRelaxEquip();
        }
        // 循环设备列表，找到合适的库位
        for (Integer equipmentId : equipmentIds) {
            // 判断一下这个设备号是否可用
            TAppEquipment thisEquipment = appEquipmentService.getById(equipmentId);
            if (thisEquipment == null) {
                // 不是可用设备
                continue;
            }
            // 设定查询条件
            LambdaQueryWrapper<TAppLocation> queryWrapper = new LambdaQueryWrapper<TAppLocation>()
                    .eq(TAppLocation::getEquipmentId, equipmentId);
            // 查询库位
            List<TAppLocation> locationList = appLocationService.list(queryWrapper);
            if (locationList == null || locationList.isEmpty()) {
                continue;
            }
            // 计算当前设备的最大深度（默认2）
            int maxDepth = locationList.stream().mapToInt(TAppLocation::getLDepth).max().orElse(2);

            // 候选库位：先按过滤条件筛选，并按 LRow -> LCol -> LLayer 排序
            List<TAppLocation> candidateLocationList = locationList.stream().filter(item -> {
                boolean filterResult = item.getIsWorking() == 0 && item.getIsLock() == 0 && item.getIsOccupy() == 0;
                if (locationFilter != null) {
                    if (locationFilter.getLRow() != null) {
                        filterResult = filterResult && Objects.equals(item.getLRow(), locationFilter.getLRow());
                    }
                    if (locationFilter.getLCol() != null) {
                        filterResult = filterResult && Objects.equals(item.getLCol(), locationFilter.getLCol());
                    }
                    if (locationFilter.getLLayer() != null) {
                        filterResult = filterResult && Objects.equals(item.getLLayer(), locationFilter.getLLayer());
                    }
                }
                return filterResult;
            }).collect(Collectors.toList());
            int maxCol = locationList.stream().mapToInt(TAppLocation::getLCol).max().orElse(86);
            candidateLocationList.sort(Comparator.comparingInt(TAppLocation::getLRow)
                    .thenComparingInt(loc -> computeColOrder(loc.getLCol(), maxCol))
                    .thenComparingInt(TAppLocation::getLLayer));

            // 若指定了 subArea，则基于上述排序优先同 subArea 的库位
            if (locationFilter != null && StringUtils.isNotEmpty(locationFilter.getSubArea())) {
                List<TAppLocation> firstList = candidateLocationList.stream()
                        .filter(item -> item.getSubArea().equals(locationFilter.getSubArea())).toList();
                List<TAppLocation> lastList = candidateLocationList.stream()
                        .filter(item -> !item.getSubArea().equals(locationFilter.getSubArea())).toList();
                candidateLocationList = new ArrayList<>(firstList);
                candidateLocationList.addAll(lastList);
            }

            // 第一轮：只尝试最大深度（例如 2 深度）库位
            for (TAppLocation candidateLocation : candidateLocationList) {
                if (!Objects.equals(candidateLocation.getLDepth(), maxDepth)) {
                    continue; // 只处理最大深度
                }
                if (candidateLocation.getIsWorking() == 1 || candidateLocation.getIsLock() == 1
                        || candidateLocation.getIsOccupy() == 1) {
                    continue;
                }
                if (isMaxDepthAvailable(locationList, candidateLocation)) {
                    try {
                        // 申请当前库位，如果成功则返回
                        if (appLocationService.update(new LambdaUpdateWrapper<TAppLocation>()
                                .set(TAppLocation::getIsOccupy, 1)
                                .set(TAppLocation::getVehicleId, requestVehicleId)
                                .eq(TAppLocation::getLocationId, candidateLocation.getLocationId())
                                .eq(TAppLocation::getIsOccupy, 0))) {
                            targetLocation = candidateLocation;
                            break;
                        }
                    } catch (Exception e) {
                        log.error("请求库位{}失败.", candidateLocation.getLocationId());
                    }
                }
            }
            if (targetLocation != null) {
                // 找到了目标库位
                break;
            }

            // 第二轮：若最大深度库位都不可用，再尝试其它深度（如 1 深度）库位
            for (TAppLocation candidateLocation : candidateLocationList) {
                if (Objects.equals(candidateLocation.getLDepth(), maxDepth)) {
                    continue; // 第一轮已经尝试
                }
                if (candidateLocation.getIsWorking() == 1 || candidateLocation.getIsLock() == 1
                        || candidateLocation.getIsOccupy() == 1) {
                    continue;
                }
                if (isMaxDepthAvailable(locationList, candidateLocation)) {
                    try {
                        // 申请当前库位，如果成功则返回
                        if (appLocationService.update(new LambdaUpdateWrapper<TAppLocation>()
                                .set(TAppLocation::getIsOccupy, 1)
                                .set(TAppLocation::getVehicleId, requestVehicleId)
                                .eq(TAppLocation::getLocationId, candidateLocation.getLocationId())
                                .eq(TAppLocation::getIsOccupy, 0))) {
                            targetLocation = candidateLocation;
                            break;
                        }
                    } catch (Exception e) {
                        log.error("请求库位{}失败.", candidateLocation.getLocationId());
                    }
                }
            }
            if (targetLocation != null) {
                // 找到了目标库位
                break;
            }
        }
        if (targetLocation != null) {
            appCommon.updateWorkingLocations(targetLocation.getLocationId(), 1);
        }

        // 返回库位，若为 null 表示无可用库位
        return targetLocation;
    }

    /**
     * 获取一个堆垛机库的空库位
     *
     * @param equipmentId 设备号
     * @return 返回的库位信息
     */
    @Override
    public TAppLocation getEmptyLocation(Integer equipmentId, WmsLocationTypeEnums type) {
        if (equipmentId == null)
            return null;
        List<TAppLocation> allLocations = appLocationService.getAllLocation(equipmentId);
        if (allLocations == null || allLocations.isEmpty())
            return null;
        for (TAppLocation location : allLocations) {
            if (location.getIsOccupy() != 0 || location.getIsLock() != 0 || location.getIsWorking() != 0) {
                continue; // 不可用货位
            }
            if (type != null && !type.getCode().equals(location.getLocationType())) {
                continue;
            }
            // 检查内侧深度是否可用
            Integer lDepth = location.getLDepth();
            if (lDepth != null && lDepth.compareTo(1) > 0) {
                boolean canUse = true;
                for (int i = lDepth - 1; i > 0; i--) {
                    int checkDepth = i;
                    List<TAppLocation> sameColLocations = allLocations.stream()
                            .filter(item -> item.getLRow().equals(location.getLRow())
                                    && item.getLCol().equals(location.getLCol())
                                    && item.getLLayer().equals(location.getLLayer())
                                    && item.getLDepth().equals(checkDepth))
                            .toList();
                    if (sameColLocations.isEmpty()) {
                        continue; // 库位不存在可能
                    }
                    TAppLocation sameColLocationsFirst = sameColLocations.getFirst();
                    // 校验是否存在库存
                    TAppStock checkIsHaveStock = new TAppStock();
                    checkIsHaveStock.setLocationId(sameColLocationsFirst.getLocationId());
                    List<TAppStock> checkStockIsHaveStockResult = appStockService.getWithEntity(checkIsHaveStock);
                    if (checkStockIsHaveStockResult == null) {
                        canUse = false; // 数据库查询失败，库位直接不可用
                        break;
                    }
                    if (!checkStockIsHaveStockResult.isEmpty()) {
                        canUse = false; // 库位有库存，不可用
                        break;
                    }
                    // 校验是否存在出入库任务
                    Boolean existsTaskWithLocation = appWcsTaskService.existsTaskWithLocation(location.getLocationId());
                    if (existsTaskWithLocation == null) {
                        canUse = false;
                        break;
                    }
                    if (existsTaskWithLocation) {
                        canUse = false; // 库位有任务，不可用
                        break;
                    }
                }
                if (!canUse) {
                    continue; // 不可用
                }
                return location;
            } else {
                // 就一个深度，直接返回可用
                return location;
            }
        }
        return null;
    }

    /**
     * 是否是最内层可用库位
     *
     * @param appLocationList 库位列表
     * @param appLocation     库位
     * @return 结果
     */
    private boolean isMaxDepthAvailable(List<TAppLocation> appLocationList, TAppLocation appLocation) {
        // 验证库位列表
        if (appLocationList == null || appLocationList.isEmpty()) {
            return false;
        }
        // 验证待查库位
        if (appLocation == null) {
            return false;
        }
        // 查询到排列层对应的库位列表
        List<TAppLocation> diffDepthLocationList = appLocationList.stream()
                .filter(item -> Objects.equals(item.getLRow(), appLocation.getLRow()) &&
                        Objects.equals(item.getLCol(), appLocation.getLCol()) &&
                        Objects.equals(item.getLLayer(), appLocation.getLLayer()) &&
                        !Objects.equals(item.getLDepth(), appLocation.getLDepth()))
                .toList();
        // 结果
        boolean result = true;
        for (TAppLocation diffDepthLocation : diffDepthLocationList) {
            if (diffDepthLocation.getIsWorking() == 1) {
                result = false;
                break;
            }
            // 深度低的库位锁定或者占用
            if (diffDepthLocation.getLDepth() < appLocation.getLDepth()) {
                if (diffDepthLocation.getIsLock() == 1 || diffDepthLocation.getIsOccupy() == 1) {
                    result = false;
                    break;
                }
            }
            // 深度高的库位未锁定或者空闲
            if (diffDepthLocation.getLDepth() > appLocation.getLDepth()) {
                if (diffDepthLocation.getIsLock() == 0 && diffDepthLocation.getIsOccupy() == 0) {
                    result = false;
                    break;
                }
            }
        }
        return result;
    }

    /**
     * 列排序权重：以列数中点为中心（86列 => 中点在43/44之间），
     * 先靠近中点的列优先，等距时优先左侧（43）再右侧（44）。
     * 计算采用整数运算：distance2 = |col*2 - (maxCol + 1)|。
     */
    private int computeColOrder(int col, int maxCol) {
        int centerTimes2 = maxCol + 1; // 偶数列的两个中心之和（如86=>87）
        int distance2 = Math.abs(col * 2 - centerTimes2); // 与中心的“距离”×2
        int side = (col <= centerTimes2 / 2) ? 0 : 1; // 左侧优先（43 再 44）
        return distance2 * 2 + side; // 组合为稳定的权重
    }

    /**
     * 找到最空闲的那台设备
     */
    private List<Integer> findMostRelaxEquip() {
        // 构造可用库位map
        Map<Integer, Integer> equipCountMap = new HashMap<>();
        // 找到可以使用的空闲库位最多的那台设备
        List<TAppLocation> emptyLocationList = appLocationService.list(new LambdaQueryWrapper<TAppLocation>()
                .eq(TAppLocation::getIsOccupy, WmsLocationOccupyStatusEnums.EMPTY.getCode())
                .eq(TAppLocation::getIsLock, WmsLockEnums.UNLOCK.getCode()));
        if (emptyLocationList.isEmpty()) {
            return Collections.emptyList();
        }
        for (TAppLocation appLocation : emptyLocationList) {
            if (!equipCountMap.containsKey(appLocation.getEquipmentId())) {
                equipCountMap.put(appLocation.getEquipmentId(), 0);
            }
        }
        // 查找到所有的入库任务列表---非暂存和完成状态。
        List<TAppTask> inTasks = appTaskService.list(new LambdaQueryWrapper<TAppTask>()
                .eq(TAppTask::getTaskType, WmsTaskTypeEnums.IN.getCode())
                .notIn(TAppTask::getTaskStatus, WmsStackerTaskStatusEnums.FINISH.getCode(),
                        WmsStackerTaskStatusEnums.TEMP.getCode()));
        if (inTasks == null || inTasks.isEmpty()) {
            for (TAppLocation appLocation : emptyLocationList) {
                if (equipCountMap.containsKey(appLocation.getEquipmentId())) {
                    equipCountMap.replace(appLocation.getEquipmentId(),
                            equipCountMap.get(appLocation.getEquipmentId()) + 1);
                }
            }
        } else {
            for (TAppTask inTask : inTasks) {
                if (StringUtils.isNotEmpty(inTask.getDestination())) {
                    // 当前目标库位的设备号
                    TAppLocation destinationEquipmentId = appCommon
                            .getInstantLocationByLocationId(inTask.getDestination());
                    if (equipCountMap.containsKey(destinationEquipmentId.getEquipmentId())) {
                        equipCountMap.replace(destinationEquipmentId.getEquipmentId(),
                                equipCountMap.get(destinationEquipmentId.getEquipmentId()) + 1);
                    }
                }
            }
        }
        if (equipCountMap.isEmpty()) {
            return Collections.emptyList();
        }
        // 排序
        return equipCountMap.entrySet().stream()
                .sorted(Comparator.comparingInt(Map.Entry::getValue))
                .map(Map.Entry::getKey)
                .toList();
    }

    /**
     * 实现
     *
     * @param wmsTasks 已完成的入库任务
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void finishStackerInTasks(List<TAppTask> wmsTasks) throws InterruptedException {
        for (TAppTask wmsTask : wmsTasks) {
            List<TAppStock> thisVehicleStocks = appStockService.list(new LambdaQueryWrapper<TAppStock>()
                    .eq(TAppStock::getVehicleId, wmsTask.getVehicleId()));
            TAppOrderIn orderIn = appOrderInService.getOne(new LambdaQueryWrapper<TAppOrderIn>()
                    .eq(TAppOrderIn::getOrderId, wmsTask.getTaskGroup())
                    .eq(TAppOrderIn::getOrderStatus, OrderStatusEnum.COMPLETE.getCode()));
            if (orderIn == null) {
                log.error("整箱入库完成更新库存失败，任务：{}，原因：没有找到符合条件的入库单", wmsTask.getTaskId());
                return;
            }
            if (thisVehicleStocks == null || thisVehicleStocks.isEmpty()) {
                TAppStock addStock = new TAppStock();
                addStock.setStockId(UUIDUtils.getNewUUID());
                addStock.setLocationId(wmsTask.getDestination());
                addStock.setVehicleId(orderIn.getVehicleNo());
                addStock.setInTaskId(orderIn.getOrderId());
                addStock.setStockStatus(WmsStockStatusEnums.OK.getCode());
                addStock.setFirstInTime(LocalDateTime.now());
                addStock.setFirstInUser("wms");
                addStock.setLastUpdateTime(null);
                addStock.setLastUpdateUser("");
                // 整箱入库直接更新库存
                if (!appStockService.save(addStock)) {
                    log.info("整箱入库完成更新库存失败，任务：{}，原因：添加库存失败", wmsTask.getTaskId());
                }
            } else {
                appStockService.update(new LambdaUpdateWrapper<TAppStock>()
                        .set(TAppStock::getStockStatus, WmsStockStatusEnums.OK.getCode())
                        .set(TAppStock::getLocationId, wmsTask.getDestination())
                        .eq(TAppStock::getVehicleId, orderIn.getVehicleNo()));
            }

            TAppVehicle vehicle = new TAppVehicle();
            vehicle.setVehicleId(wmsTask.getVehicleId());
            vehicle.setVehicleStatus(WmsVehicleStatusEnums.ON.getCode());
            vehicle.setIsLock(0);
            vehicle.setLocationId(wmsTask.getDestination());
            vehicle.setLastInTime(LocalDateTime.now());
            appVehicleService.saveOrUpdate(vehicle);

            appCommon.updateWorkingLocations(wmsTask.getDestination(), 0);
            // 备份并删除任务
            if (!appTaskService.removeById(wmsTask.getTaskId())) {
                log.info("删除入库任务失败，任务：{}", wmsTask.getTaskId());
            }
            if (!appTaskBakService.save(wmsTask.of())) {
                log.info("备份入库任务失败，任务：{}", wmsTask.getTaskId());
            }
            if (!appOrderInService.removeById(orderIn.getRecordId())) {
                log.info("整箱入库完成删除入库单失败，任务：{}，原因：删除入库单失败", wmsTask.getTaskId());
            }

            OrderInCBReq orderInCBReq = new OrderInCBReq();
            orderInCBReq.setTaskId(orderIn.getOrderId());
            orderInCBReq.setVehicleNo(wmsTask.getVehicleId());
            orderInCBReq.setLocationId(wmsTask.getDestination());
            orderInCBReq.setResult(OrderInCBEnums.COMPLETE.getCode());
            orderInCBReq.setResultMessage("入库完成");

            int times = 0;
            MesApiResponse response = null;
            do {
                if (times > 5) {
                    break;
                }
                Thread.sleep(15000L * times);
                response = externalApiService.invokeOrderInCB(orderInCBReq);
                times++;
            } while (response.getCode() != 0);
            if (response.getCode() != 0) {
                log.error("[wms]上报失败");
            } else {
                log.info("[wms]上报成功");
            }
        }
    }

    /**
     * 实现
     *
     * @param stackerTransferTasks 已完成的移库任务
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void finishStackerTransferTasks(List<TAppTask> stackerTransferTasks) {
        for (TAppTask wmsTask : stackerTransferTasks) {
            List<TAppStock> thisVehicleStocks = appStockService.list(new LambdaQueryWrapper<TAppStock>()
                    .eq(TAppStock::getVehicleId, wmsTask.getVehicleId()));
            appStockService.update(new LambdaUpdateWrapper<TAppStock>()
                    .in(TAppStock::getStockId, thisVehicleStocks.stream().map(TAppStock::getStockId).toList())
                    .set(TAppStock::getLocationId, wmsTask.getDestination())
                    .set(TAppStock::getStockStatus, WmsStockStatusEnums.OK.getCode()));
            appLocationService.update(new LambdaUpdateWrapper<TAppLocation>()
                    .eq(TAppLocation::getLocationId, wmsTask.getOrigin())
                    .set(TAppLocation::getIsOccupy, WmsLocationOccupyStatusEnums.EMPTY.getCode())
                    .set(TAppLocation::getVehicleId, ""));
            appVehicleService.update(new LambdaUpdateWrapper<TAppVehicle>()
                    .eq(TAppVehicle::getVehicleId, wmsTask.getVehicleId())
                    .set(TAppVehicle::getLocationId, wmsTask.getDestination()));
            appCommon.updateWorkingLocations(wmsTask.getDestination(), 0);
            appCommon.updateWorkingLocations(wmsTask.getOrigin(), 0);
            appTaskService.removeById(wmsTask.getTaskId());
            appTaskBakService.save(wmsTask.of());
        }
    }

    /**
     * 实现
     *
     * @param stackerOutTasks 已完成的出库任务
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void finishStackerOutTasks(List<TAppTask> stackerOutTasks) throws InterruptedException {
        // 出库完成需要完成以下事情：
        // 1. 更新库存状态
        // 2. 更新载具状态
        // 3. 释放库位
        // 4. 释放当前载具的拣选任务列表
        // 5. 添加出库记录
        // 根据载具号map一下
        Map<String, List<TAppTask>> vehicleIdToTaskMap = stackerOutTasks.stream()
                .filter(outTask -> Objects.equals(outTask.getTaskType(), WmsTaskTypeEnums.OUT.getCode())
                        && Objects.equals(outTask.getTaskStatus(), WmsStackerTaskStatusEnums.FINISH.getCode()))
                .collect(Collectors.groupingBy(TAppTask::getVehicleId));
        for (String vehicleId : vehicleIdToTaskMap.keySet()) {
            // 查询当前载具的数据
            TAppVehicle thisVehicle = appVehicleService.getOne(new LambdaQueryWrapper<TAppVehicle>()
                    .eq(TAppVehicle::getVehicleId, vehicleId));
            if (thisVehicle == null || StringUtils.isEmpty(thisVehicle.getLocationId())) {
                // 必须要有载具信息
                log.warn("载具{}的出库任务完成处理失败，原因：缺少载具信息（库位必须）。", vehicleId);
                // 将当前载具所有的任务状态都设置为异常
                appTaskService.update(new LambdaUpdateWrapper<TAppTask>()
                        .set(TAppTask::getTaskStatus, WmsStackerTaskStatusEnums.EXCEPTION.getCode())
                        .set(TAppTask::getRemark, "缺少载具信息（库位必须），出库完成处理失败。")
                        .eq(TAppTask::getTaskType, WmsTaskTypeEnums.OUT.getCode())
                        .eq(TAppTask::getVehicleId, vehicleId));
                continue;
            }
            // 释放当前库位
            appLocationService.update(new LambdaUpdateWrapper<TAppLocation>()
                    .set(TAppLocation::getIsOccupy, WmsLocationOccupyStatusEnums.EMPTY.getCode())
                    .set(TAppLocation::getVehicleId, "")
                    .eq(TAppLocation::getLocationId, thisVehicle.getLocationId())
                    .eq(TAppLocation::getVehicleId, vehicleId));
            // 更新载具信息
            appCommon.updateWorkingLocations(thisVehicle.getLocationId(), 0);
            thisVehicle.setVehicleStatus(WmsVehicleStatusEnums.OUT.getCode());
            thisVehicle.setLocationId("");
            appVehicleService.updateById(thisVehicle);
            // 更新当前载具对应的所有库存的状态为已出库
            appStockService.update(new LambdaUpdateWrapper<TAppStock>()
                    .set(TAppStock::getStockStatus, WmsStockStatusEnums.OUTED.getCode())
                    .set(TAppStock::getLocationId, "")
                    .eq(TAppStock::getVehicleId, vehicleId));
            // 当前载具的任务列表
            List<TAppTask> thisVehicleOutTasks = vehicleIdToTaskMap.get(vehicleId);
            if (thisVehicleOutTasks.isEmpty()) {
                continue;
            }
            List<String> orderIds = thisVehicleOutTasks.stream().map(TAppTask::getTaskGroup).distinct().toList();
            List<TAppOrderOut> orderOuts = appOrderOutService.list(new LambdaQueryWrapper<TAppOrderOut>()
                    .in(TAppOrderOut::getOrderId, orderIds));
            if (!thisVehicleOutTasks.isEmpty()) {
                // 存储出库记录
                List<TAppTaskBak> stockOutRecordList = thisVehicleOutTasks.stream()
                        .map(TAppTask::of).toList();
                appTaskBakService.saveBatch(stockOutRecordList);
                // 删除当前载具所对应的出库任务
                appTaskService.remove(new LambdaQueryWrapper<TAppTask>()
                        .eq(TAppTask::getVehicleId, vehicleId)
                        .eq(TAppTask::getTaskType, WmsTaskTypeEnums.OUT.getCode())
                        .in(TAppTask::getTaskId, thisVehicleOutTasks.stream().map(TAppTask::getTaskId).toList()));
                // 使用流删除关联的出库订单实体（新增的核心部分）
                if (!orderOuts.isEmpty()) {
                    appOrderOutService.removeBatchByIds(orderOuts);
                }
            }
            for (TAppOrderOut orderOut : orderOuts) {
                OrderOutCBReq orderOutCBReq = new OrderOutCBReq();
                orderOutCBReq.setTaskId(orderOut.getOrderId());
                orderOutCBReq.setVehicleNo(vehicleId);
                orderOutCBReq.setResult(OrderOutCBEnums.COMPLETE.getCode());
                orderOutCBReq.setResultMessage("出库完成");

                int times = 0;
                MesApiResponse response = null;
                do {
                    if (times > 5) {
                        break;
                    }
                    response = externalApiService.invokeOrderOutCB(orderOutCBReq);
                    times++;
                    Thread.sleep(15000L * times);
                } while (response.getCode() != 0);
                if (response.getCode() != 0) {
                    log.error("[WMS]上报失败");
                } else {
                    log.info("[WMS]上报成功");
                }
            }
        }
    }
}
