package org.wcs.business.stacker.impl;

import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.wcs.business.stacker.StackerTaskCreator;
import org.wcs.business.stacker.intf.IExecuteStackerTaskService;
import org.wcs.business.stock.intf.IStockSingleTaskExecuteEvent;
import org.wcs.constant.ConstantData;
import org.wcs.constant.enums.business.SseEventTypeEnum;
import org.wcs.constant.enums.common.TrueOrFalseEnum;
import org.wcs.constant.enums.database.StackerStandInTypeEnum;
import org.wcs.constant.enums.database.StockSingleTaskStatusEnum;
import org.wcs.constant.enums.database.StockSingleTaskTypeEnum;
import org.wcs.helper.PlcTaskIdHelper;
import org.wcs.helper.SseHelper;
import org.wcs.mapper.intf.AppStackerStandService;
import org.wcs.mapper.intf.AppStockSingleTaskService;
import org.wcs.model.bo.tuple.Tuple2;
import org.wcs.model.po.app.AppStackerInfo;
import org.wcs.model.po.app.AppStackerStand;
import org.wcs.model.po.app.AppStockSingleTask;
import org.wcs.plugin.plc.PlcCommunicationFactory;
import org.wcs.plugin.plc.model.StackerTask;
import org.wcs.plugin.plc.model.TaskConveyStatus;
import org.wcs.utils.AppListUtils;
import org.wcs.utils.AppStringUtils;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Objects;

/**
 * 执行堆垛机任务方法
 */
@Slf4j
@Service
@RequiredArgsConstructor
public class ExecuteStackerTaskService implements IExecuteStackerTaskService {


    private final AppStockSingleTaskService stockSingleTaskDao; // 任务表操作类
    private final AppStackerStandService stackerStandDao; // 堆垛机站台表操作类
    private final StackerTaskCreator stackerTaskCreator; // 堆垛机任务创建类
    private final PlcTaskIdHelper plcTaskIdHelper; // PLC任务ID生成类
    private final IStockSingleTaskExecuteEvent stockSingleTaskExecuteEvent; // 独立任务执行 事件
    private final SseHelper sseHelper; // SSE连接



    /**
     * 执行堆垛机入库任务
     * @param stackerInfo 堆垛机信息
     * @return 是否执行了任务
     */
    @Override
    public boolean executeStackerInTask(AppStackerInfo stackerInfo) {
        List<AppStockSingleTask> stockSingleTasks = stockSingleTaskDao.queryTask(StockSingleTaskStatusEnum.CREATE.getCode());
        if(stockSingleTasks == null || stockSingleTasks.isEmpty()) {
            return false;   // 查询失败或者没有任务，不执行下面动作
        }
        // 查找这个堆垛机所有的入库站台
        List<AppStackerStand> stackerStands = stackerStandDao.queryStackerStand(stackerInfo.getStackerId());
        if(stackerStands == null || stackerStands.isEmpty()) {
            return false;   // 堆垛机没有站台，不执行下面动作
        }
        List<AppStackerStand> stackerInStands = stackerStands.stream().filter(stand -> stand.getAllowIn() == TrueOrFalseEnum.TRUE.getCode()).toList();
        if(stackerInStands.isEmpty()) {
            return false;   // 堆垛机没有入库站台，不执行下面动作
        }
        for (AppStackerStand stackerInStand : stackerInStands) {
            if(stackerInStand.getInType().equals(StackerStandInTypeEnum.CHECK_CODE.getCode())) {
                // 根据站台条码入库
                var isexe = executeStackerCheckCodeTask(stackerInfo, stackerInStand);
                if(isexe) {
                    return true;
                }
            }
            if(stackerInStand.getInType().equals(StackerStandInTypeEnum.IMMEDIATELY.getCode())) {
                // 站台检测有货立即入库
                var isexe = executeStackerImmediatelyTask(stackerInfo, stackerInStand);
                if(isexe) {
                    return true;
                }
            }
        }
        return false;
    }


    /**
     * 执行堆垛机出库任务
     * @param stackerInfo 堆垛机信息
     * @return 是否执行了任务
     */
    @Override
    public boolean executeStackerOutTask(AppStackerInfo stackerInfo) {
        Integer stackerId = stackerInfo.getStackerId();
        /* 判断出库最高优先级和移库最高优先级哪个高 */
        List<AppStockSingleTask> stockSingleOutTasks = stockSingleTaskDao.queryStackerTask(stackerId, StockSingleTaskStatusEnum.CREATE.getCode(), StockSingleTaskTypeEnum.STACKER_OUT.getCode());
        if(stockSingleOutTasks == null || stockSingleOutTasks.isEmpty()) {
            return false;   // 查询失败或者没有任务，不执行下面动作
        }
        Integer outPriority = stockSingleOutTasks.getFirst().getPriority();
        List<AppStockSingleTask> stockSingleMoveTasks = stockSingleTaskDao.queryStackerTask(stackerId, StockSingleTaskStatusEnum.CREATE.getCode(), StockSingleTaskTypeEnum.STACKER_MOVE.getCode());
        Integer movePriority = stockSingleMoveTasks == null || stockSingleMoveTasks.isEmpty() ? 0 : stockSingleMoveTasks.getFirst().getPriority();
        if(outPriority.compareTo(movePriority) < 0) {
            // 出库优先级低于移库优先级，出库暂停执行
            return false;
        }
        /* 校验货叉状态 */
        String forkStatus = stackerInfo.getForkStatus();
        if(AppStringUtils.isEmpty(forkStatus)) {
            return false;
        }
        // 查询站台信息
        List<AppStackerStand> stackerStands = stackerStandDao.queryStackerStand(stackerId);
        if(stackerStands == null || stackerStands.isEmpty()) {
            return false;   // 堆垛机站台信息查询失败
        }
        List<AppStackerStand> outStands = stackerStands.stream().filter(stand -> stand.getAllowOut() == TrueOrFalseEnum.TRUE.getCode()).toList();
        if(outStands.isEmpty()) {
            return false;   // 堆垛机没有出库站台
        }
        /* 处理拉取到的任务 */
        // 查找需要执行的任务
        Tuple2<List<AppStockSingleTask>, AppStackerStand> needOutTaskListTuple = getExecuteStackerOutTasks(stockSingleOutTasks, outStands, forkStatus.length());
        List<AppStockSingleTask> needOutTaskList = needOutTaskListTuple.item1;
        AppStackerStand standInfo = needOutTaskListTuple.item2;
        if(needOutTaskList == null || needOutTaskList.isEmpty()) {
                return false; // 没有要执行的
        }
        List<AppStockSingleTask> executeTasks = new ArrayList<>(); // 将要执行的任务
        List<StackerTask> tasks = new ArrayList<>(); // 即将要写入堆垛机的任务
        for (int i = 0; i < forkStatus.length(); i++) {
            if (needOutTaskList.size() <= i || !String.valueOf(forkStatus.charAt(i)).equals(String.valueOf(TrueOrFalseEnum.TRUE.getCode()))) {
                tasks.add(null);
                continue;
            }
            AppStockSingleTask stockSingleTask = needOutTaskList.get(i); // 获取该游标的任务
            StackerTask task = stackerTaskCreator.createStackerOutTask(stockSingleTask.getPlcTaskId(), stockSingleTask.getOrigin(), standInfo.getStandId(), stockSingleTask.getVehicleNo(), stockSingleTask.getVehicleSize().shortValue(), stockSingleTask.getWeight().shortValue());
            if(task == null) {
                tasks.add(null);
            } else {
                tasks.add(task);
                executeTasks.add(stockSingleTask);
            }
        }
        // 校验任务是不是都是 null 或者执行的任务是空
        if(tasks.stream().allMatch(Objects::isNull) || executeTasks.isEmpty()) {
            return false;
        }
        // 写入任务
        StackerTask[] tasksArray = tasks.toArray(new StackerTask[0]);
        String writeStackerTaskErrTask = PlcCommunicationFactory.getPlcCommunicationByPlcId(stackerInfo.getPlcId()).writeStackerTask(stackerId, tasksArray);
        if(AppStringUtils.isNotEmpty(writeStackerTaskErrTask)) {
            log.info("堆垛机写入出库任务失败：{}；写入的任务为：{}", writeStackerTaskErrTask, AppListUtils.listObjectToSting(tasks));
            sseHelper.SendEventToAll(SseEventTypeEnum.RUNNING_INFO, "堆垛机写入出库任务失败：" + tasks.getFirst().getPlcTaskId() + " 等" + tasks.size() + "个任务");
            return false;
        }
        // 堆垛机写入任务成功
        log.info("堆垛机写入出库任务成功：{}", AppListUtils.listObjectToSting(tasks));
        sseHelper.SendEventToAll(SseEventTypeEnum.RUNNING_INFO, "堆垛机写入出库任务：" + tasks.getFirst().getPlcTaskId() + " 等" + tasks.size() + "个任务");
        // 触发任务开始执行事件
        for (AppStockSingleTask executeTask : executeTasks) {
            stockSingleTaskExecuteEvent.taskStart(executeTask, "任务开始执行");
        }
        return true;
    }

    /**
     * 获取堆垛机出库任务
     * @param stockSingleTaskList 堆垛机任务列表
     * @param outStands 出库站台列表
     * @param selectNum 需要选择的数量
     * @return 堆垛机出库任务列表
     */
    private Tuple2<List<AppStockSingleTask>, AppStackerStand> getExecuteStackerOutTasks(List<AppStockSingleTask> stockSingleTaskList,List<AppStackerStand> outStands, int selectNum) {
        List<AppStockSingleTask> returnList = new ArrayList<>(); // 需要返回的任务
        AppStackerStand standInfo = null; // 本次的出库站台
        for (AppStockSingleTask stockSingleTaskItem : stockSingleTaskList) {
            if(returnList.size() >= selectNum) {
                return new Tuple2<>(returnList, standInfo); // 已经选择够数量了
            }
            if(AppStringUtils.isEmpty(stockSingleTaskItem.getDestination())) { // 纯空的
                // 获取一个可以出库的站台
                if(standInfo == null) {
                    standInfo = checkOutStandCanUse(outStands);
                }
                if(standInfo == null) {
                    return new Tuple2<>(returnList, standInfo); // 这种随便选的都没有满足条件的就表示所有的都不满足，直接返回了
                }
                stockSingleTaskItem.setDestination(standInfo.getStandId());
                returnList.add(stockSingleTaskItem);
                continue;
            }
            if(stockSingleTaskItem.getDestination().startsWith("?")) { // 问号开头的表示备选的站台已经确定，只能在这几个站台内选择
                String[] spareStands = stockSingleTaskItem.getDestination().replace("?", "").split(";"); // 备选站台
                AppStackerStand finalStandInfo = standInfo;
                // 如果本次选择已经确定了站台，并且此任务也可以选择此站台则直接将此任务加入
                if(finalStandInfo != null && Arrays.stream(spareStands).anyMatch(standId -> standId.equals(finalStandInfo.getStandId()))) {
                    stockSingleTaskItem.setDestination(standInfo.getStandId());
                    returnList.add(stockSingleTaskItem);
                    continue;
                }
                if(standInfo == null) {
                    standInfo = checkOutStandCanUseWithStandIdList(Arrays.stream(spareStands).toList());
                    if(standInfo == null) {
                        continue; // 没找到合适位置
                    }
                    // 找到了合适的位置
                    stockSingleTaskItem.setDestination(standInfo.getStandId());
                    returnList.add(stockSingleTaskItem);
                    continue;
                }
                // 本次寻找的站台已经确定，并且此任务可以出库的站台不是已经确定的站台
                continue;
            }
            // 任务终点内已经确定站台的出库
            String destination = stockSingleTaskItem.getDestination(); // 终点站台
            if(standInfo != null && !destination.equals(standInfo.getStandId())) {
                continue; // 站台已经确定，但是终点站台和站台不匹配
            }
            if(standInfo == null) {
                standInfo = checkOutStandCanUseWithStandIdList(List.of(destination)); // 站台没确定，此处主要检验一下是否能出库
            }
            if(standInfo == null) {
                continue; // 站台不存在或者不允许出库
            }
            stockSingleTaskItem.setDestination(standInfo.getStandId());
            returnList.add(stockSingleTaskItem);
            continue;
        }
        return new Tuple2<>(returnList, standInfo);
    }

    /**
     * 执行堆垛机移库任务
     * @param stackerInfo 堆垛机信息
     * @return 是否执行了任务
     */
    @Override
    public boolean executeStackerMoveTask(AppStackerInfo stackerInfo) {
        Integer stackerId = stackerInfo.getStackerId();
        /* 判断移库最高优先级和出库最高优先级哪个高 */
        List<AppStockSingleTask> stockSingleMoveTasks = stockSingleTaskDao.queryStackerTask(stackerId, StockSingleTaskStatusEnum.CREATE.getCode(), StockSingleTaskTypeEnum.STACKER_MOVE.getCode());
        if(stockSingleMoveTasks == null || stockSingleMoveTasks.isEmpty()) {
            return false; // 查询失败或者没有任务，不执行下面动作
        }
        Integer movePriority = stockSingleMoveTasks.getFirst().getPriority();
        List<AppStockSingleTask> stockSingleOutTasks = stockSingleTaskDao.queryStackerTask(stackerId, StockSingleTaskStatusEnum.CREATE.getCode(), StockSingleTaskTypeEnum.STACKER_OUT.getCode());
        Integer outPriority = stockSingleOutTasks == null || stockSingleOutTasks.isEmpty() ? 0 : stockSingleOutTasks.getFirst().getPriority();
        if(movePriority.compareTo(outPriority) < 0) {
            // 移库优先级低于出库优先级，移库暂停执行
            return false;
        }
        /* 校验货叉状态 */
        String forkStatus = stackerInfo.getForkStatus();
        if(AppStringUtils.isEmpty(forkStatus)) {
            return false;
        }
        List<AppStockSingleTask> executeTasks = new ArrayList<>(); // 执行的任务
        List<StackerTask> tasks = new ArrayList<>(); // 即将要写入堆垛机的任务
        for(int i = 0; i < forkStatus.length(); i++) {
            if (!String.valueOf(forkStatus.charAt(i)).equals(String.valueOf(TrueOrFalseEnum.TRUE.getCode())) || stockSingleMoveTasks.size() <= i) {
                tasks.add(null);
                continue;
            }
            AppStockSingleTask stockSingleTask = stockSingleMoveTasks.get(i); // 移库任务
            StackerTask task = stackerTaskCreator.createStackerMoveTask(stockSingleTask.getPlcTaskId(), stockSingleTask.getOrigin(), stockSingleTask.getDestination(), stockSingleTask.getVehicleNo(), stockSingleTask.getVehicleSize().shortValue(), stockSingleTask.getWeight().shortValue());
            if(task == null) {
                tasks.add(null);
            } else {
                tasks.add(task);
                executeTasks.add(stockSingleTask);
            }
        }
        // 校验任务是不是都是 null
        if(tasks.stream().allMatch(Objects::isNull) || executeTasks.isEmpty()) {
            return false;
        }
        // 写入任务
        StackerTask[] tasksArray = tasks.toArray(new StackerTask[0]);
        String writeStackerTaskErrTask = PlcCommunicationFactory.getPlcCommunicationByPlcId(stackerInfo.getPlcId()).writeStackerTask(stackerId, tasksArray);
        if(AppStringUtils.isNotEmpty(writeStackerTaskErrTask)) {
            log.info("堆垛机写入移库任务失败：{}；写入的任务为：{}", writeStackerTaskErrTask, AppListUtils.listObjectToSting(tasks));
            sseHelper.SendEventToAll(SseEventTypeEnum.RUNNING_INFO, "堆垛机写入移库任务失败：" + tasks.getFirst().getPlcTaskId() + " 等" + tasks.size() + "个任务");
            return false;
        }
        // 堆垛机写入任务成功
        log.info("堆垛机写入移库任务成功：{}", AppListUtils.listObjectToSting(tasks));
        sseHelper.SendEventToAll(SseEventTypeEnum.RUNNING_INFO, "堆垛机写入移库任务：" + tasks.getFirst().getPlcTaskId() + " 等" + tasks.size() + "个任务");
        // 触发任务开始执行事件
        for (AppStockSingleTask executeTask : executeTasks) {
            stockSingleTaskExecuteEvent.taskStart(executeTask, "任务开始执行");
        }
        return true;
    }


    /**
     * 执行堆垛机入库任务 ---- 检验入库站台条码
     * @param stackerInfo 堆垛机信息
     * @param standInfo 站台信息
     * @return 是否执行了任务
     */
    private boolean executeStackerCheckCodeTask(AppStackerInfo stackerInfo, AppStackerStand standInfo) {
        Integer stackerId = stackerInfo.getStackerId();
        /* 校验货叉状态 */
        String forkStatus = stackerInfo.getForkStatus();
        if(AppStringUtils.isEmpty(forkStatus)) {
            return false;
        }
        Tuple2<String, List<TaskConveyStatus>> multiConveyStatusResult = PlcCommunicationFactory.getPlcCommunicationByPlcId(standInfo.getPlcId()).readTaskMultiConveyStatus(standInfo.getStandId());
        if(AppStringUtils.isNotEmpty(multiConveyStatusResult.item1)) {
            return false; // 读取站台信息存在异常
        }
        List<TaskConveyStatus> conveyStatuses = multiConveyStatusResult.item2;
        if(conveyStatuses.size() != forkStatus.length()) {
            return false; // 站台信息数量和货叉数量不一致
        }
        List<AppStockSingleTask> executeTasks = new ArrayList<>(); // 执行的任务
        List<StackerTask> tasks = new ArrayList<>(); // 即将要写入堆垛机的任务
        for (int i = 0; i < conveyStatuses.size(); i++) {
            if (!String.valueOf(forkStatus.charAt(i)).equals(String.valueOf(TrueOrFalseEnum.TRUE.getCode()))) {
                tasks.add(null);
                continue;
            }
            TaskConveyStatus conveyStatus = conveyStatuses.get(i);
            String vehicleNo = conveyStatus.getVehicleNo(); // 载具号
            if(conveyStatus.getPlcTaskId() != 0 || conveyStatus.getDeviceStatus().intValue() != 5 || conveyStatus.getTaskAllow().intValue() != TrueOrFalseEnum.TRUE.getCode()
                    || conveyStatus.getSensor().intValue() == TrueOrFalseEnum.TRUE.getCode() || AppStringUtils.isEmpty(vehicleNo)) {
                // 任务号不为0；设备状态不为5；任务不允许；载具号为空 ---- 这些情况不搬运
                tasks.add(null);
                continue;
            }
            /* 检查这个载具号的入库任务 */
            List<AppStockSingleTask> stockSingleTasks = vehicleNo.equals(ConstantData.NO_READ) ? new ArrayList<>() : stockSingleTaskDao.queryStackerTask(stackerId, vehicleNo, StockSingleTaskStatusEnum.CREATE.getCode(), StockSingleTaskTypeEnum.STACKER_IN.getCode());
            if(stockSingleTasks == null) {  // 数据库查询失败
                tasks.add(null);
                continue;
            }
            if(stockSingleTasks.isEmpty()) {    // 这个载具没有任务或者读码失败
                AppStackerStand canUseOutStand = getCanUseOutStand(stackerId); // 获取一个出库站台
                if(canUseOutStand == null) {    // 没有可用的出库站台
                    return false;
                }
                Integer plcTaskId = plcTaskIdHelper.newTaskId(); // 获取一个 PLC任务ID
                if(plcTaskId == null) {
                    return false;
                }
                // 构造异常搬出的任务
                StackerTask stackerErrTask = stackerTaskCreator.createStackerErrTask(plcTaskId, standInfo.getStandName(), canUseOutStand.getStandName(), vehicleNo);
                tasks.add(stackerErrTask);
                log.info("堆垛机：{} 载具：{} 在：{} 找不到入库任务，生成异常任务，搬运到：{}", stackerId, vehicleNo, standInfo.getStandId(), canUseOutStand.getStandId());
                continue;
            }
            // 载具存在入库任务
            AppStockSingleTask stockSingleTask = stockSingleTasks.getFirst(); // 要执行的入库任务
            StackerTask stackerInTask = stackerTaskCreator.createStackerInTask(stockSingleTask.getPlcTaskId(), standInfo.getStandName(), stockSingleTask.getDestination(), vehicleNo, stockSingleTask.getVehicleSize().shortValue(), stockSingleTask.getWeight().shortValue());
            if(stackerInTask == null) {
                tasks.add(null);
            } else {
                tasks.add(stackerInTask);
                executeTasks.add(stockSingleTask);
            }
        }
        // 校验任务是不是都是 null
        if(tasks.stream().allMatch(Objects::isNull) || executeTasks.isEmpty()) {
            return false;
        }
        // 写入堆垛机任务
        StackerTask[] tasksArray = tasks.toArray(new StackerTask[0]);
        String writeStackerTaskErrTask = PlcCommunicationFactory.getPlcCommunicationByPlcId(stackerInfo.getPlcId()).writeStackerTask(stackerId, tasksArray);
        if(AppStringUtils.isNotEmpty(writeStackerTaskErrTask)) {
            log.info("堆垛机写入入库任务失败：{}；写入的任务为：{}", writeStackerTaskErrTask, AppListUtils.listObjectToSting(tasks));
            return false;
        }
        // 堆垛机写入任务成功
        log.info("堆垛机写入入库任务成功：{}", AppListUtils.listObjectToSting(tasks));
        // 触发任务开始执行事件
        for (AppStockSingleTask executeTask : executeTasks) {
            stockSingleTaskExecuteEvent.taskStart(executeTask, "任务开始执行");
        }
        return true;
    }

    /**
     * 执行堆垛机入库任务 ---- 立即入库
     * @param stackerInfo 堆垛机信息
     * @param standInfo 站台信息
     * @return 是否执行了任务
     */
    private boolean executeStackerImmediatelyTask(AppStackerInfo stackerInfo, AppStackerStand standInfo) {
        Integer stackerId = stackerInfo.getStackerId();
        /* 查询入库任务 */
        List<AppStockSingleTask> stockSingleTasks = stockSingleTaskDao.queryStackerTask(stackerId, StockSingleTaskStatusEnum.CREATE.getCode(), StockSingleTaskTypeEnum.STACKER_IN.getCode());
        if(stockSingleTasks == null || stockSingleTasks.isEmpty()) {
            return false;
        }
        /* 检查各种任务优先级 */
        Integer inMaxPriority = stockSingleTasks.getFirst().getPriority(); // 入库最高优先级
        List<AppStockSingleTask> stockSingleOutTasks = stockSingleTaskDao.queryStackerTask(stackerId, StockSingleTaskStatusEnum.CREATE.getCode(), StockSingleTaskTypeEnum.STACKER_OUT.getCode());
        Integer outPriority = stockSingleOutTasks == null || stockSingleOutTasks.isEmpty() ? 0 : stockSingleOutTasks.getFirst().getPriority(); // 出库高优先级
        List<AppStockSingleTask> stockSingleMoveTasks = stockSingleTaskDao.queryStackerTask(stackerId, StockSingleTaskStatusEnum.CREATE.getCode(), StockSingleTaskTypeEnum.STACKER_MOVE.getCode());
        Integer movePriority = stockSingleMoveTasks == null || stockSingleMoveTasks.isEmpty() ? 0 : stockSingleMoveTasks.getFirst().getPriority(); // 移库最高优先级
        if(inMaxPriority.compareTo(outPriority) < 0 || inMaxPriority.compareTo(movePriority) < 0) {
            return false; // 入库优先级低，先不执行
        }
        /* 校验货叉状态 */
        String forkStatus = stackerInfo.getForkStatus();
        if(AppStringUtils.isEmpty(forkStatus)) {
            return false;
        }
        // 读取站台信息，这里考虑多工位会返回多个，单工位只会返回一个
        Tuple2<String, List<TaskConveyStatus>> multiConveyStatusResult = PlcCommunicationFactory.getPlcCommunicationByPlcId(standInfo.getPlcId()).readTaskMultiConveyStatus(standInfo.getStandId());
        if(AppStringUtils.isNotEmpty(multiConveyStatusResult.item1)) {
            return false; // 读取站台信息存在异常
        }
        List<TaskConveyStatus> conveyStatuses = multiConveyStatusResult.item2;
        if(conveyStatuses.size() != forkStatus.length()) {
            return false; // 站台信息数量和货叉数量不一致
        }
        List<AppStockSingleTask> executeTasks = new ArrayList<>(); // 执行的任务
        List<StackerTask> tasks = new ArrayList<>(); // 即将要写入堆垛机的任务
        for(int i = 0; i < forkStatus.length(); i++) {
            // 货叉开放检查
            if (!String.valueOf(forkStatus.charAt(i)).equals(String.valueOf(TrueOrFalseEnum.TRUE.getCode()))) {
                tasks.add(null);
                continue;
            }
            TaskConveyStatus conveyStatus = conveyStatuses.get(i);
            //String vehicleNo = conveyStatus.getVehicleNo(); // 载具号
            if(conveyStatus.getPlcTaskId() != 0 || conveyStatus.getDeviceStatus().intValue() != 5 || conveyStatus.getTaskAllow().intValue() != TrueOrFalseEnum.TRUE.getCode()
                    || conveyStatus.getSensor().intValue() == TrueOrFalseEnum.TRUE.getCode() || conveyStatus.getErrCode() != 0) {
                // 任务号不为0；设备状态不为5；任务不允许；载具号为空，存在AGV ---- 这些情况不搬运
                tasks.add(null);
                continue;
            }
            StackerTask stackerInTask = null; // 要写入的任务
            // 查询站台数量
            List<AppStackerStand> stackerStands = stackerStandDao.queryStackerStand(stackerId);
            if(stackerStands == null) {
                return false;   // 堆垛机查询站台失败
            }
            int standCount = stackerStands.size();
            // 轮询任务
            for (AppStockSingleTask stockSingleTask : stockSingleTasks) {
                // 检查任务是否上回已经添加进去了
                List<AppStockSingleTask> checkIsExecute = executeTasks.stream().filter(task -> task.getTaskId().equals(stockSingleTask.getTaskId())).toList();
                if(!checkIsExecute.isEmpty()) {
                    continue;
                }
                /* 校验入库位置是否为空，若不为空则判断入库位置是否和现在站台一致 */
                String origin = stockSingleTask.getOrigin();
                // 入库站台为空，判断这个堆垛机是否只有一个入库站台，不是则跳过
                if(AppStringUtils.isEmpty(origin) && standCount > 1) {
                    continue;
                }
                // 不是空
                if(AppStringUtils.isNotEmpty(origin) && !origin.equals(standInfo.getStandId())) {
                    continue; // 不是空但是入库站台不对应跳过
                }
                stackerInTask = stackerTaskCreator.createStackerInTask(stockSingleTask.getPlcTaskId(), standInfo.getStandId(), stockSingleTask.getDestination(), stockSingleTask.getVehicleNo(), stockSingleTask.getVehicleSize().shortValue(), stockSingleTask.getWeight().shortValue());
                if(stackerInTask == null) {
                    continue;
                }
                tasks.add(stackerInTask);
                executeTasks.add(stockSingleTask);
                break;
            }
            if(stackerInTask == null) {
                tasks.add(null);
            }
        }
        // 校验任务是不是都是 null
        if(tasks.stream().allMatch(Objects::isNull) || executeTasks.isEmpty()) {
            return false;
        }
        // 写入堆垛机任务
        StackerTask[] tasksArray = tasks.toArray(new StackerTask[0]);
        String writeStackerTaskErrTask = PlcCommunicationFactory.getPlcCommunicationByPlcId(stackerInfo.getPlcId()).writeStackerTask(stackerId, tasksArray);
        if(AppStringUtils.isNotEmpty(writeStackerTaskErrTask)) {
            log.info("堆垛机写入直入式入库任务失败：{}；写入的任务为：{}", writeStackerTaskErrTask, AppListUtils.listObjectToSting(tasks));
            sseHelper.SendEventToAll(SseEventTypeEnum.RUNNING_INFO, "堆垛机写入入库任务失败：" + tasks.getFirst().getPlcTaskId() + " 等" + tasks.size() + "个任务");
            return false;
        }
        // 堆垛机写入任务成功
        log.info("堆垛机写入直入式入库任务成功：{}", AppListUtils.listObjectToSting(tasks));
        sseHelper.SendEventToAll(SseEventTypeEnum.RUNNING_INFO, "堆垛机写入入库任务：" + tasks.getFirst().getPlcTaskId() + " 等" + tasks.size() + "个任务");
        // 触发任务开始执行事件
        for (AppStockSingleTask executeTask : executeTasks) {
            stockSingleTaskExecuteEvent.taskStart(executeTask, "任务开始执行");
        }
        return true;
    }


    /* ************************************* 外部工具方法 ****************************************** */

    /**
     * 获取可出库的站台信息
     * @param stackerId 堆垛机ID
     * @return 可出库的站台信息
     */
    private AppStackerStand getCanUseOutStand(Integer stackerId) {
        List<AppStackerStand> stackerStands = stackerStandDao.queryStackerStand(stackerId);
        return checkOutStandCanUse(stackerStands);
    }


    /**
     * 获取可出库的站台信息
     * @param standInfoList 站台信息列表
     * @return 可出库的站台信息
     */
    private AppStackerStand checkOutStandCanUse(List<AppStackerStand> standInfoList) {
        if(standInfoList == null || standInfoList.isEmpty()) {
            return null;
        }
        for (AppStackerStand standInfo : standInfoList) {
            if(!standInfo.getAllowOut().equals(TrueOrFalseEnum.TRUE.getCode())) {
                continue; // 站台不允许出库
            }
            if(checkOutStandCanUse(standInfo)) {
                return standInfo;
            }
        }
        return null;
    }

    /**
     * 获取可出库的站台信息
     * @param standList 站台ID列表
     * @return 可出库的站台信息
     */
    private AppStackerStand checkOutStandCanUseWithStandIdList(List<String> standList) {
        List<AppStackerStand> stackerStands = stackerStandDao.queryStackerStand(standList);
        return checkOutStandCanUse(stackerStands);
    }


    /**
     * 检查出库站台是否可用
     * @param standInfo 站台信息
     * @return 是否可用
     */
    private boolean checkOutStandCanUse(AppStackerStand standInfo) {
        /* 检查站台状态是否可用 */
        Tuple2<String, List<TaskConveyStatus>> multiConveyStatusResult = PlcCommunicationFactory.getPlcCommunicationByPlcId(standInfo.getPlcId()).readTaskMultiConveyStatus(standInfo.getStandId());
        if(AppStringUtils.isNotEmpty(multiConveyStatusResult.item1) || multiConveyStatusResult.item2 == null || multiConveyStatusResult.item2.isEmpty()) {
            return false; // 读取站台失败
        }
        // 判断站台的状态
        boolean canUse = true;
        List<TaskConveyStatus> multiConveyStatus = multiConveyStatusResult.item2;
        for(TaskConveyStatus conveyStatus : multiConveyStatus) {
            if (conveyStatus.getPlcTaskId() == 0 && conveyStatus.getDeviceStatus().intValue() != 5 && conveyStatus.getTaskAllow().intValue() == TrueOrFalseEnum.TRUE.getCode()
                    && conveyStatus.getSensor().intValue() == TrueOrFalseEnum.FALSE.getCode() && conveyStatus.getErrCode().intValue() == 0) {
                continue; // 站台状态可用
            }
            canUse = false;
        }
        return canUse;
    }


    /* ************************************* 外部工具方法 END ****************************************** */
}
