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.AppConstant;
import com.wms_main.constant.enums.wms.*;
import com.wms_main.dao.*;
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.business.IStackerTaskService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.time.LocalDate;
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 ITAppPickTaskService appPickTaskService;
    /**
     * 设备服务
     */
    private final ITAppEquipmentService appEquipmentService;
    /**
     * 业务通用
     */
    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);
            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;
                    }).sorted(Comparator.comparingInt(TAppLocation::getLDepth).reversed())
                    .sorted(Comparator.comparingInt(location -> location.getLCol() + location.getLLayer()))
                    .toList();
            // 判断是否输入了subArea
            if (locationFilter != null && StringUtils.isNotEmpty(locationFilter.getSubArea())) {
                // 对candidateLocationList进行排序
                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);// 先添加符合subArea的库位
                candidateLocationList.addAll(lastList);// 再添加不符合subArea的库位
            }
            // 找一个空闲的库位
            for (TAppLocation candidateLocation : candidateLocationList) {
                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;
            }
        }

        // 返回库位，如果返回null则表示没有可用库位
        return targetLocation;
    }

    /**
     * 是否是最内层可用库位
     *
     * @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;
    }

    /**
     * 找到最空闲的那台设备
     */
    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 stackerInTasks 已完成的入库任务
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void finishStackerInTasks(List<TAppTask> stackerInTasks) {
        // 入库任务完成需要做以下几件事情：
        // 1. 生成库存，如果是已有库存则更新库存状态、数量、库位这些信息。
        // 2. 添加载具信息，如果载具已经存在则更新状态、库位等信息。
        // 3. 添加入库记录。
        // 4. 不同入库时间的库存要分开
        // 根据载具号map一下
        Map<String, List<TAppTask>> vehicleIdToTaskMap = stackerInTasks.stream()
                .filter(inTask -> Objects.equals(inTask.getTaskType(), WmsTaskTypeEnums.IN.getCode()) && Objects.equals(inTask.getTaskStatus(), WmsStackerTaskStatusEnums.FINISH.getCode()))
                .collect(Collectors.groupingBy(TAppTask::getVehicleId));
        for (String vehicleId : vehicleIdToTaskMap.keySet()) {
            List<TAppTask> thisVehicleInTasks = vehicleIdToTaskMap.get(vehicleId);
            // 查询这个载具的信息
            TAppVehicle thisVehicle = appVehicleService.getOne(new LambdaQueryWrapper<TAppVehicle>()
                    .eq(TAppVehicle::getVehicleId, vehicleId)
            );
            // 查询这个载具的库存
            List<TAppStock> thisVehicleStocks = appStockService.list(
                    new LambdaQueryWrapper<TAppStock>()
                            .eq(TAppStock::getVehicleId, vehicleId));
            // 遍历任务信息
            List<String> goodsIds = new ArrayList<>();
            // 新的库存信息
            List<TAppStock> newStockList = new ArrayList<>();
            // 入库记录
            List<TAppTaskBak> newTaskBakList = new ArrayList<>();
            // 需要删除的任务id
            List<String> needDeleteTaskIds = new ArrayList<>();
            for (TAppTask thisVehicleInTask : thisVehicleInTasks) {
                // 任务记录
                newTaskBakList.add(new TAppTaskBak(
                        thisVehicleInTask.getTaskId(),
                        thisVehicleInTask.getTaskType(),
                        thisVehicleInTask.getTaskStatus(),
                        thisVehicleInTask.getTaskPriority(),
                        thisVehicleInTask.getVehicleId(),
                        thisVehicleInTask.getOrigin(),
                        thisVehicleInTask.getDestination(),
                        thisVehicleInTask.getWcsTaskId(),
                        thisVehicleInTask.getCreateTime(),
                        thisVehicleInTask.getFinishTime(),
                        thisVehicleInTask.getGoodsId(),
                        thisVehicleInTask.getOpNum(),
                        thisVehicleInTask.getStockNum(),
                        thisVehicleInTask.getOpUser(),
                        thisVehicleInTask.getRemark(),
                        thisVehicleInTask.getCallStand(),
                        thisVehicleInTask.getGoodsDesc(),
                        thisVehicleInTask.getBarCode(),
                        thisVehicleInTask.getMesId()
                ));
                // 删除任务
                needDeleteTaskIds.add(thisVehicleInTask.getTaskId());
                // 判断是否需要更新库存信息
                if (!Objects.equals(thisVehicleInTask.getGoodsId(), AppConstant.EMPTY_GOODS_ID)) {
                    goodsIds.add(thisVehicleInTask.getGoodsId());
                    TAppGoods thisGoods = appCommon.getInstantGoodsByGoodsId(thisVehicleInTask.getGoodsId());
                    Integer sledDays = null;// null表示非有效期管理
                    LocalDate expireDate = null;// null表示非有效期管理
                    if (thisGoods != null && Objects.equals(thisGoods.getPutArea(), "ASRS") && thisGoods.getIsSled().contains("Y")) {
                        // 有效期管理的物料
                        if (thisGoods.getSledDays() != null) {
                            sledDays = thisGoods.getSledDays();
                            expireDate = thisVehicleInTask.getCreateTime().plusDays(sledDays).toLocalDate();
                        }
                    }
                    // 新库存，增加库存信息
                    newStockList.add(new TAppStock(
                            UUIDUtils.getNewUUID(),
                            vehicleId,
                            thisVehicleInTask.getDestination(),
                            WmsStockStatusEnums.OK.getCode(),
                            thisVehicleInTask.getGoodsId(),
                            WmsGoodsStatusEnums.OK.getCode(),
                            thisVehicleInTask.getCreateTime(),
                            thisVehicleInTask.getOpUser(),
                            LocalDateTime.now(),
                            thisVehicleInTask.getOpUser(),
                            thisVehicleInTask.getOpNum(),
                            thisVehicleInTask.getOpNum(),
                            thisVehicleInTask.getOpNum(),
                            thisVehicleInTask.getGoodsDesc(),
                            expireDate,
                            sledDays,
                            thisVehicleInTask.getBarCode(),
                            thisVehicleInTask.getMesId()
                    ));
                }
            }
            // 当前载具是否是空载具
            boolean isEmptyVehicle = goodsIds.isEmpty() && thisVehicleStocks.isEmpty();
            if (thisVehicle == null) {
                // 新建一个载具信息
                thisVehicle = new TAppVehicle(
                        vehicleId,
                        isEmptyVehicle ? 1 : 0,
                        WmsVehicleStatusEnums.ON.getCode(),
                        "",
                        0,
                        thisVehicleInTasks.getFirst().getDestination(),
                        LocalDateTime.now()
                );
            } else {
                // 更新已有载具信息
                thisVehicle.setIsEmpty(isEmptyVehicle ? 1 : 0);
                thisVehicle.setVehicleStatus(WmsVehicleStatusEnums.ON.getCode());
                thisVehicle.setLastInTime(LocalDateTime.now());
                thisVehicle.setLocationId(thisVehicleInTasks.getFirst().getDestination());
            }
            // 保存载具信息
            appVehicleService.saveOrUpdate(thisVehicle);
            // 将目标库位的工作状态设置为未工作
            appLocationService.update(new LambdaUpdateWrapper<TAppLocation>()
                    .set(TAppLocation::getIsWorking, 0)
                    .eq(TAppLocation::getLocationId, thisVehicle.getLocationId())
            );
            // 需要更新下当前载具下的库存其他信息
            appStockService.update(new LambdaUpdateWrapper<TAppStock>()
                    .set(TAppStock::getStockStatus, WmsStockStatusEnums.OK.getCode())
                    .set(TAppStock::getLocationId, thisVehicleInTasks.getFirst().getDestination())
                    .eq(TAppStock::getVehicleId, vehicleId));
            // 保存库存信息
            if (!newStockList.isEmpty()) {
                appStockService.saveOrUpdateBatch(newStockList);
            }
            // 添加任务记录
            if (!newTaskBakList.isEmpty()) {
                appTaskBakService.saveBatch(newTaskBakList);
            }
            // 删除已经完成的入库任务
            if (!needDeleteTaskIds.isEmpty()) {
                appTaskService.removeByIds(needDeleteTaskIds);
            }
        }
    }

    /**
     * 实现---这里是合并库存的部分
     *
     * @param stackerInTasks 已完成的入库任务
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void finishStackerInTasksMergeSameGoods(List<TAppTask> stackerInTasks) {
        // 入库任务完成需要做以下几件事情：
        // 1. 生成库存，如果是已有库存则更新库存状态、数量、库位这些信息。
        // 2. 添加载具信息，如果载具已经存在则更新状态、库位等信息。
        // 3. 添加入库记录。
        // 根据载具号map一下
        Map<String, List<TAppTask>> vehicleIdToTaskMap = stackerInTasks.stream()
                .filter(inTask -> Objects.equals(inTask.getTaskType(), WmsTaskTypeEnums.IN.getCode()) && Objects.equals(inTask.getTaskStatus(), WmsStackerTaskStatusEnums.FINISH.getCode()))
                .collect(Collectors.groupingBy(TAppTask::getVehicleId));
        for (String vehicleId : vehicleIdToTaskMap.keySet()) {
            List<TAppTask> thisVehicleInTasks = vehicleIdToTaskMap.get(vehicleId);
            // 查询这个载具的信息
            TAppVehicle thisVehicle = appVehicleService.getOne(new LambdaQueryWrapper<TAppVehicle>()
                    .eq(TAppVehicle::getVehicleId, vehicleId)
            );
            // 查询这个载具的库存
            List<TAppStock> thisVehicleStocks = appStockService.list(
                    new LambdaQueryWrapper<TAppStock>()
                            .eq(TAppStock::getVehicleId, vehicleId));
            // 遍历任务信息
            List<String> goodsIds = new ArrayList<>();
            // 新的库存信息
            List<TAppStock> newStockList = new ArrayList<>();
            // 待删除的库存信息
            List<String> needDeleteStockIds = new ArrayList<>();
            // 入库记录
            List<TAppTaskBak> newTaskBakList = new ArrayList<>();
            // 需要删除的任务id
            List<String> needDeleteTaskIds = new ArrayList<>();
            for (TAppTask thisVehicleInTask : thisVehicleInTasks) {
                // 任务记录
                newTaskBakList.add(new TAppTaskBak(
                        thisVehicleInTask.getTaskId(),
                        thisVehicleInTask.getTaskType(),
                        thisVehicleInTask.getTaskStatus(),
                        thisVehicleInTask.getTaskPriority(),
                        thisVehicleInTask.getVehicleId(),
                        thisVehicleInTask.getOrigin(),
                        thisVehicleInTask.getDestination(),
                        thisVehicleInTask.getWcsTaskId(),
                        thisVehicleInTask.getCreateTime(),
                        thisVehicleInTask.getFinishTime(),
                        thisVehicleInTask.getGoodsId(),
                        thisVehicleInTask.getOpNum(),
                        thisVehicleInTask.getStockNum(),
                        thisVehicleInTask.getOpUser(),
                        thisVehicleInTask.getRemark(),
                        thisVehicleInTask.getCallStand(),
                        "",
                        thisVehicleInTask.getGoodsDesc(),
                        thisVehicleInTask.getBarCode()
                ));
                // 删除任务
                needDeleteTaskIds.add(thisVehicleInTask.getTaskId());
                // 判断是否需要更新库存信息
                if (Objects.equals(thisVehicleInTask.getGoodsId(), AppConstant.EMPTY_GOODS_ID)) {
                    // 空载具或者回库任务
                    continue;
                } else {
                    goodsIds.add(thisVehicleInTask.getGoodsId());
                }
                List<TAppStock> oldStockList = thisVehicleStocks.stream()
                        .filter(stock -> Objects.equals(stock.getGoodsId(), thisVehicleInTask.getGoodsId()))
                        .toList();
                TAppGoods thisGoods = appCommon.getInstantGoodsByGoodsId(thisVehicleInTask.getGoodsId());
                Integer sledDays = null;// -1表示非有效期管理
                LocalDate expireDate = null;// null表示非有效期管理
                if (thisGoods != null && Objects.equals(thisGoods.getPutArea(), "ASRS") && thisGoods.getIsSled().contains("Y")) {
                    // 有效期管理的物料
                    if (thisGoods.getSledDays() != null) {
                        sledDays = thisGoods.getSledDays();
                        expireDate = thisVehicleInTask.getCreateTime().plusDays(sledDays).toLocalDate();
                    }
                }
                if (oldStockList.isEmpty()) {
                    // 新库存，增加库存信息
                    newStockList.add(new TAppStock(
                            UUIDUtils.getNewUUID(),
                            vehicleId,
                            thisVehicleInTask.getDestination(),
                            WmsStockStatusEnums.OK.getCode(),
                            thisVehicleInTask.getGoodsId(),
                            WmsGoodsStatusEnums.OK.getCode(),
                            thisVehicleInTask.getCreateTime(),
                            thisVehicleInTask.getOpUser(),
                            LocalDateTime.now(),
                            thisVehicleInTask.getOpUser(),
                            thisVehicleInTask.getOpNum(),
                            thisVehicleInTask.getOpNum(),
                            thisVehicleInTask.getOpNum(),
                            thisVehicleInTask.getGoodsDesc(),
                            expireDate,
                            sledDays,
                            thisVehicleInTask.getBarCode(),
                            thisVehicleInTask.getMesId()
                    ));
                } else {
                    // 更新已有库存信息
                    if (oldStockList.size() > 1) {
                        // 需要合并库存信息
                        int originSum = oldStockList.stream()
                                .mapToInt(TAppStock::getRealNum)
                                .sum();
                        int originTotal = oldStockList.stream()
                                .mapToInt(TAppStock::getTotalNum)
                                .sum();
                        // 新库存，增加库存信息
                        newStockList.add(new TAppStock(
                                UUIDUtils.getNewUUID(),
                                vehicleId,
                                thisVehicleInTask.getDestination(),
                                WmsStockStatusEnums.OK.getCode(),
                                thisVehicleInTask.getGoodsId(),
                                WmsGoodsStatusEnums.OK.getCode(),
                                oldStockList.getFirst().getFirstInTime(),
                                oldStockList.getFirst().getFirstInUser(),
                                LocalDateTime.now(),
                                thisVehicleInTask.getOpUser(),
                                originTotal + thisVehicleInTask.getOpNum(),
                                originSum + thisVehicleInTask.getOpNum(),
                                originSum + thisVehicleInTask.getOpNum(),
                                thisVehicleInTask.getGoodsDesc(),
                                expireDate,
                                sledDays,
                                thisVehicleInTask.getBarCode(),
                                thisVehicleInTask.getMesId()
                        ));
                        needDeleteStockIds.addAll(oldStockList.stream()
                                .map(TAppStock::getStockId)
                                .toList());
                    } else {
                        TAppStock oldStock = oldStockList.getFirst();
                        // 更新数量
                        oldStock.setRealNum(oldStock.getRealNum() + thisVehicleInTask.getOpNum());
                        oldStock.setRemainNum(oldStock.getRealNum());
                        oldStock.setTotalNum(oldStock.getTotalNum() + thisVehicleInTask.getOpNum());
                        // 更新库位
                        oldStock.setLocationId(thisVehicleInTask.getDestination());
                        oldStock.setLastUpdateTime(LocalDateTime.now());
                        oldStock.setLastUpdateUser(thisVehicleInTask.getOpUser());
                        oldStock.setStockStatus(WmsStockStatusEnums.OK.getCode());
                        newStockList.add(oldStock);
                    }
                }
            }
            // 当前载具是否是空载具
            boolean isEmptyVehicle = goodsIds.isEmpty() && thisVehicleStocks.isEmpty();
            if (thisVehicle == null) {
                // 新建一个载具信息
                thisVehicle = new TAppVehicle(
                        vehicleId,
                        isEmptyVehicle ? 1 : 0,
                        WmsVehicleStatusEnums.ON.getCode(),
                        "",
                        0,
                        thisVehicleInTasks.getFirst().getDestination(),
                        LocalDateTime.now()
                );
            } else {
                // 更新已有载具信息
                thisVehicle.setIsEmpty(isEmptyVehicle ? 1 : 0);
                thisVehicle.setVehicleStatus(WmsVehicleStatusEnums.ON.getCode());
                thisVehicle.setLastInTime(LocalDateTime.now());
                thisVehicle.setLocationId(thisVehicleInTasks.getFirst().getDestination());
            }
            // 保存载具信息
            appVehicleService.saveOrUpdate(thisVehicle);
            // 将目标库位的工作状态设置为未工作
            appLocationService.update(new LambdaUpdateWrapper<TAppLocation>()
                    .set(TAppLocation::getIsWorking, 0)
                    .eq(TAppLocation::getLocationId, thisVehicle.getLocationId())
            );
            // 删除多余的库存信息
            if (!needDeleteStockIds.isEmpty()) {
                appStockService.removeByIds(needDeleteStockIds);
            }
            // 需要更新下当前载具下的库存其他信息
            appStockService.update(new LambdaUpdateWrapper<TAppStock>()
                    .set(TAppStock::getStockStatus, WmsStockStatusEnums.OK.getCode())
                    .set(TAppStock::getLocationId, thisVehicleInTasks.getFirst().getDestination())
                    .eq(TAppStock::getVehicleId, vehicleId)
            );
            // 保存库存信息
            if (!newStockList.isEmpty()) {
                appStockService.saveOrUpdateBatch(newStockList);
            }
            // 添加任务记录
            if (!newTaskBakList.isEmpty()) {
                appTaskBakService.saveBatch(newTaskBakList);
            }
            // 删除已经完成的入库任务
            if (!needDeleteTaskIds.isEmpty()) {
                appTaskService.removeByIds(needDeleteTaskIds);
            }
        }
    }

    /**
     * 实现
     *
     * @param stackerOutTasks 已完成的出库任务
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void finishStackerOutTasks(List<TAppTask> stackerOutTasks) {
        // 出库完成需要完成以下事情：
        // 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, "")
                    .set(TAppLocation::getIsWorking, 0)
                    .eq(TAppLocation::getLocationId, thisVehicle.getLocationId())
                    .eq(TAppLocation::getVehicleId, vehicleId));
            // 更新载具信息
            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));
            // 释放当前载具对应的拣选任务
            appPickTaskService.update(new LambdaUpdateWrapper<TAppPickTask>()
                    .set(TAppPickTask::getPickStatus, WmsPickTaskStatusEnum.WAIT.getCode())
                    .eq(TAppPickTask::getVehicleId, vehicleId)
                    .eq(TAppPickTask::getPickStatus, WmsPickTaskStatusEnum.TEMP.getCode()));
            // 当前载具的任务列表
            List<TAppTask> thisVehicleOutTasks = vehicleIdToTaskMap.get(vehicleId);
            if (!thisVehicleOutTasks.isEmpty()) {
                // 存储出库记录
                List<TAppTaskBak> stockOutRecordList = thisVehicleOutTasks.stream()
                        .map(outTask -> new TAppTaskBak(
                                outTask.getTaskId(),
                                outTask.getTaskType(),
                                outTask.getTaskStatus(),
                                outTask.getTaskPriority(),
                                outTask.getVehicleId(),
                                outTask.getOrigin(),
                                outTask.getDestination(),
                                outTask.getWcsTaskId(),
                                outTask.getCreateTime(),
                                outTask.getFinishTime(),
                                outTask.getGoodsId(),
                                outTask.getOpNum(),
                                outTask.getStockNum(),
                                outTask.getOpUser(),
                                outTask.getRemark(),
                                outTask.getCallStand(),
                                "",
                                outTask.getBarCode(),
                                outTask.getMesId()
                        )).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()));
            }
        }
    }
}
