package org.wcs.quartzJob;

import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.quartz.DisallowConcurrentExecution;
import org.quartz.Job;
import org.quartz.JobExecutionContext;
import org.wcs.business.data.intf.IDataRecorder;
import org.wcs.business.pub.ReportStandard;
import org.wcs.business.stock.LocationManage;
import org.wcs.business.stock.StockComposeTaskManage;
import org.wcs.constant.enums.database.StockComposeTaskStatusEnum;
import org.wcs.constant.enums.database.StockComposeTaskStepStatusEnum;
import org.wcs.constant.enums.database.StockComposeTaskTypeEnum;
import org.wcs.constant.enums.database.StockSingleTaskStatusEnum;
import org.wcs.constant.enums.http.StockCallBackStatusEnum;
import org.wcs.helper.AppConfigHelper;
import org.wcs.helper.LocationHelper;
import org.wcs.mapper.intf.AppStockComposeTaskBakService;
import org.wcs.mapper.intf.AppStockComposeTaskService;
import org.wcs.mapper.intf.AppStockSingleTaskBakService;
import org.wcs.mapper.intf.AppStockSingleTaskService;
import org.wcs.model.bo.tuple.Tuple2;
import org.wcs.model.po.app.AppStockComposeTask;
import org.wcs.model.po.app.AppStockComposeTaskBak;
import org.wcs.model.po.app.AppStockSingleTask;
import org.wcs.model.po.app.AppStockSingleTaskBak;
import org.wcs.utils.AppBeanUtils;
import org.wcs.utils.AppDataBaseTransUtils;
import org.wcs.utils.AppStringUtils;

import java.time.LocalDateTime;
import java.util.Comparator;
import java.util.List;

/**
 * 【核心】核心定时器，仓库任务解析器，包括 堆垛机任务，托盘线任务，输送线任务，四项车任务，AGV任务
 * 核心逻辑为 从 composeTask 表中查询任务，解析后存入 singleTask 表中
 */
@Slf4j
@DisallowConcurrentExecution
@RequiredArgsConstructor
public class ResolveStockTaskJob implements Job {

    private final StockComposeTaskManage stockComposeTaskManage;
    private final AppStockComposeTaskService stockComposeTaskService;
    private final AppStockComposeTaskBakService stockComposeTaskBakService;
    private final AppStockSingleTaskService stockSingleTaskService;
    private final AppStockSingleTaskBakService stockSingleTaskBakService;
    private final AppDataBaseTransUtils transUtils;
    private final IDataRecorder dataRecorder;
    private final AppConfigHelper configHelper;
    private final LocationHelper locationHelper;
    private final LocationManage locationManage; // 仓库位置管理器

    static boolean stockComposeTaskManageInitialized = false;

    @Override
    public void execute(JobExecutionContext jobExecutionContext) {
        if(!stockComposeTaskManageInitialized) {
            try {
                stockComposeTaskManage.initialize();
                stockComposeTaskManageInitialized = true;
                log.info("定时任务：解析任务数据初始化完成");
            } catch (Exception e) {
                return;
            }
        }
        locationManage.loadOnceLocation(); // 仓库位置管理器初始化
        /* 处理新建任务 */
        List<AppStockComposeTask> newTaskList = stockComposeTaskService.queryWithStatus(StockComposeTaskStatusEnum.CREATE.getCode());
        resolveNewStockTask(newTaskList); // 处理新建任务
        /* 处理正在执行的任务 */
        List<AppStockComposeTask> executingTaskList = stockComposeTaskService.queryWithStatus(StockComposeTaskStatusEnum.EXECUTING.getCode());
        resolveExecutingStockTask(executingTaskList);
        /* 处理已经做完或者已经取消的任务 */
        List<AppStockComposeTask> endTaskList = stockComposeTaskService.queryWithStatus(StockComposeTaskStatusEnum.COMPLETE.getCode(), StockComposeTaskStatusEnum.CANCEL.getCode());
        resolveEndStockTask(endTaskList);
        /* 处理超时任务 */
        List<AppStockComposeTask> timeoutTaskList = stockComposeTaskService.queryWithStatus(StockComposeTaskStatusEnum.TIMEOUT.getCode());
        resolveTimeoutStockTask(timeoutTaskList);
        /* 处理任务异常的任务 */
        List<AppStockComposeTask> errorTaskList = stockComposeTaskService.queryWithStatus(StockComposeTaskStatusEnum.ERROR.getCode());
        resolveErrorStockTask(errorTaskList);
    }

    /**
     * 处理新任务
     * @param stockComposeTaskList 新任务列表
     */
    private void resolveNewStockTask(List<AppStockComposeTask> stockComposeTaskList) {
        /* 主要功能，校验任务数据是否合法，不合法取消任务，合法的生成子任务 */
        stockComposeTaskList.forEach(stockComposeTask -> {
            log.info("处理新仓库任务：{}", AppStringUtils.objectToString(stockComposeTask));
            // 初步检查
            String dataCheckErrText = StockComposeTaskTypeEnum.getByCode(stockComposeTask.getTaskType()).getStockTaskDataCheck().checkStockTaskData(stockComposeTask);
            if(AppStringUtils.isNotEmpty(dataCheckErrText)) {
                stockComposeTaskService.setTaskStatusAndMsg(stockComposeTask.getTaskId(), StockComposeTaskStatusEnum.CANCEL,StockComposeTaskStepStatusEnum.ERROR, dataCheckErrText);
                dataRecorder.recordStockMsg(stockComposeTask.getTaskId(), stockComposeTask.getVehicleNo(), dataCheckErrText);
                return;
            }
            if(stockComposeTask.getTaskType().equals(StockComposeTaskTypeEnum.AUTO.getCode())) { // ---- 自动的暂时不做，存在问题
                // 自动任务生成新任务
                Tuple2<String, AppStockSingleTask> firstAutoStockSingleTaskTuple = stockComposeTaskManage.createFirstAutoStockSingleTask(stockComposeTask);
                if(AppStringUtils.isEmpty(firstAutoStockSingleTaskTuple.item1)) {
                    // 任务创建成功，插入新独立任务，将组合任务更新成执行中
                    boolean createTransResult = transUtils.useTran(() -> {
                        stockSingleTaskService.insert(firstAutoStockSingleTaskTuple.item2);
                        stockComposeTaskService.setTaskStatusAndMsg(stockComposeTask.getTaskId(), StockComposeTaskStatusEnum.QUEUE, StockComposeTaskStepStatusEnum.CREATE, "任务解析完成");
                    });
                    if(!createTransResult) {
                        log.info("初次任务创建失败，组合任务ID：{}，数据库事务执行失败", stockComposeTask.getTaskId());
                        dataRecorder.recordStockMsg(stockComposeTask.getTaskId(), stockComposeTask.getVehicleNo(), "初次任务创建失败，插入任务时数据库事务执行失败");
                        return;
                    }
                    dataRecorder.recordStockMsg(stockComposeTask.getTaskId(), stockComposeTask.getVehicleNo(), "任务解析完成");
                    log.info("初次任务创建成功，组合任务ID：{}", stockComposeTask.getTaskId());
                    return;
                }
                log.info("初次任务创建失败，组合任务ID：{}，错误信息：{}", stockComposeTask.getTaskId(), firstAutoStockSingleTaskTuple.item1);
                dataRecorder.recordStockMsg(stockComposeTask.getTaskId(), stockComposeTask.getVehicleNo(), "初次任务创建失败，错误信息：" + firstAutoStockSingleTaskTuple.item1);
                stockComposeTaskService.setTaskStatusAndMsg(stockComposeTask.getTaskId(), StockComposeTaskStatusEnum.CANCEL,StockComposeTaskStepStatusEnum.ERROR, firstAutoStockSingleTaskTuple.item1);
                return;
            }
            if(StockComposeTaskTypeEnum.autoCalculateCourseType(stockComposeTask.getTaskType())) {  // 自动计算的路径
                if(!stockComposeTask.getTaskType().equals(StockComposeTaskTypeEnum.IN.getCode()) && AppStringUtils.isEmpty(stockComposeTask.getOrigin())) {
                    // 不是入库任务，并且起点为空，任务取消
                    String errText = "非入库任务不允许存在起点为空";
                    log.info("任务解析失败，组合任务ID：{}，错误信息：{}", stockComposeTask.getTaskId(), errText);
                    dataRecorder.recordStockMsg(stockComposeTask.getTaskId(), stockComposeTask.getVehicleNo(), "初次任务创建失败，错误信息：" + errText);
                    stockComposeTaskService.setTaskStatusAndMsg(stockComposeTask.getTaskId(), StockComposeTaskStatusEnum.CANCEL,StockComposeTaskStepStatusEnum.ERROR, errText);
                    return;
                }
                Tuple2<String, AppStockSingleTask> stockSingleTask = stockComposeTaskManage.createStockSingleTask(stockComposeTask, stockComposeTask.getOrigin(), stockComposeTask.getDestination());
                if(AppStringUtils.isEmpty(stockSingleTask.item1)) {
                    // 任务创建成功，插入新独立任务，将组合任务更新成执行中
                    boolean createTransResult = transUtils.useTran(() -> {
                        stockSingleTaskService.insert(stockSingleTask.item2);
                        stockComposeTaskService.setTaskStatusAndMsg(stockComposeTask.getTaskId(), StockComposeTaskStatusEnum.QUEUE, StockComposeTaskStepStatusEnum.CREATE, "任务解析完成");
                    });
                    if(!createTransResult) {
                        log.info("组合任务解析 创建失败，组合任务ID：{}，数据库事务执行失败", stockComposeTask.getTaskId());
                        dataRecorder.recordStockMsg(stockComposeTask.getUpperTaskId(), stockComposeTask.getVehicleNo(), "初次任务创建失败，插入任务时数据库事务执行失败");
                        return;
                    }
                    dataRecorder.recordStockMsg(stockComposeTask.getUpperTaskId(), stockComposeTask.getVehicleNo(), "任务解析完成");
                    log.info("组合任务解析 创建成功，组合任务ID：{}", stockComposeTask.getTaskId());
                    return;
                }
                log.info("组合任务解析 创建失败，组合任务ID：{}，错误信息：{}", stockComposeTask.getTaskId(), stockSingleTask.item1);
                dataRecorder.recordStockMsg(stockComposeTask.getUpperTaskId(), stockComposeTask.getVehicleNo(), "初次任务创建失败，错误信息：" + stockSingleTask.item1);
                stockComposeTaskService.setTaskStatusAndMsg(stockComposeTask.getTaskId(), StockComposeTaskStatusEnum.CANCEL, StockComposeTaskStepStatusEnum.ERROR, stockSingleTask.item1);
                return;
            }
        });
    }

    /**
     * 处理执行中的任务
     * @param executingTaskList 执行中的任务列表
     */
    private void resolveExecutingStockTask(List<AppStockComposeTask> executingTaskList) {
        executingTaskList.forEach(executingTask -> {
            // 判断是否超时
            String composeTaskTimeout = configHelper.getConfig("COMPOSE_TASK_TIMEOUT");
            composeTaskTimeout = composeTaskTimeout == null ? "180" : composeTaskTimeout;
            if(executingTask.getStartTime().plusMinutes(Long.parseLong(composeTaskTimeout)).isBefore(LocalDateTime.now())) {
                stockComposeTaskService.setTaskStatusAndMsg(executingTask.getTaskId(), StockComposeTaskStatusEnum.CANCEL, StockComposeTaskStepStatusEnum.ERROR, "超时自动取消，超时时间：" + composeTaskTimeout + " 分钟");
                dataRecorder.recordStockMsg(executingTask.getUpperTaskId(), executingTask.getVehicleNo(), "任务超时自动取消，超时时间：" + composeTaskTimeout + " 分钟");
                return;
            }
            // 根据子任务判断动作
            List<AppStockSingleTask> stockSingleTasks = stockSingleTaskService.queryByUpperTaskId(executingTask.getUpperTaskId());
            if(stockSingleTasks == null) {
                return; // 查询失败
            }
            if(stockSingleTasks.isEmpty()) {
                return; // 没有任务
            }
            stockSingleTasks.sort(Comparator.comparingInt(AppStockSingleTask::getPriority).reversed());
            AppStockSingleTask stockSingleTask = stockSingleTasks.getFirst();
            if(stockSingleTask.getTaskStatus().equals(StockSingleTaskStatusEnum.CANCEL.getCode())) {
                // 任务取消，一并取消组合任务
                stockComposeTaskService.setTaskStatusAndMsg(executingTask.getTaskId(), StockComposeTaskStatusEnum.CANCEL, StockComposeTaskStepStatusEnum.ERROR, "任务取消，信息：" + stockSingleTask.getTaskMsg());
                dataRecorder.recordStockMsg(executingTask.getUpperTaskId(), executingTask.getVehicleNo(), "任务取消，信息：" + stockSingleTask.getTaskMsg());
                return;
            }
            if(stockSingleTask.getTaskStatus().equals(StockSingleTaskStatusEnum.COMPLETE.getCode())) {
                // 子任务完成
                String businessDestinationLocationId = locationHelper.getBusinessLocationId(stockSingleTask.getDestination());
                if(businessDestinationLocationId == null) {
                    return;
                }
                if(AppStringUtils.isEmpty(executingTask.getDestination()) || businessDestinationLocationId.equals(executingTask.getDestination())) {
                    // 组合任务终点为空或者子任务终点等于组合任务终点，任务完成
                    stockComposeTaskService.setTaskStatusAndMsg(executingTask.getTaskId(), StockComposeTaskStatusEnum.COMPLETE, StockComposeTaskStepStatusEnum.COMPLETE,"任务完成");
                    dataRecorder.recordStockMsg(executingTask.getUpperTaskId(), executingTask.getVehicleNo(), "任务完成");
                    log.info("任务完成，组合任务ID：{}", executingTask.getTaskId());
                    return;
                }
                // 子任务终点不等于组合任务终点，任务继续，生成下一个任务
                Tuple2<String, AppStockSingleTask> nextAutoStockSingleTaskResult = stockComposeTaskManage.createStockSingleTask(executingTask, stockSingleTask.getDestination(), executingTask.getDestination());
                if(nextAutoStockSingleTaskResult.getItem1() != null) {
                    log.info("生成下一个任务失败，组合任务ID：{}，错误信息：{}", executingTask.getTaskId(), nextAutoStockSingleTaskResult.getItem1());
                    dataRecorder.recordStockMsg(executingTask.getUpperTaskId(), executingTask.getVehicleNo(), "生成下一个任务失败，错误信息：" + nextAutoStockSingleTaskResult.getItem1());
                    stockComposeTaskService.setTaskStatusAndMsg(executingTask.getTaskId(), StockComposeTaskStatusEnum.ERROR, StockComposeTaskStepStatusEnum.ERROR,  "生成下一个任务失败，错误信息：" + nextAutoStockSingleTaskResult.getItem1());
                    return;
                }
                AppStockSingleTask nextAutoStockSingleTask = nextAutoStockSingleTaskResult.getItem2();
                boolean insert = stockSingleTaskService.insert(nextAutoStockSingleTask);
                if(!insert) {
                    log.info("生成下一个任务失败，组合任务ID：{}，错误信息：数据服务异常", executingTask.getTaskId());
                }
                stockComposeTaskService.setTaskStatusAndMsg(executingTask.getTaskId(), StockComposeTaskStatusEnum.EXECUTING, StockComposeTaskStepStatusEnum.RUNNING, "接续任务创建：" + nextAutoStockSingleTask.getTaskId());
                dataRecorder.recordStockMsg(executingTask.getUpperTaskId(), executingTask.getVehicleNo(), "接续任务创建：" + nextAutoStockSingleTask.getTaskId());
                log.info("任务继续，组合任务ID：{}", executingTask.getTaskId());
            }
            // 其他任务类型不处理
        });
    }

    /**
     * 处理已结束的任务 ---- 完成或者取消
     * @param endTaskList 已结束任务列表
     */
    private void resolveEndStockTask(List<AppStockComposeTask> endTaskList) {
        for (AppStockComposeTask composeTask : endTaskList) {
            List<AppStockSingleTask> stockSingleTasks = stockSingleTaskService.queryByUpperTaskId(composeTask.getUpperTaskId());
            if(stockSingleTasks == null) {
                continue;
            }
            /* 完成任务 */
            if(composeTask.getTaskStatus().equals(StockComposeTaskStatusEnum.COMPLETE.getCode())) {
                Tuple2<String, String> reporterResult = ReportStandard.stockTaskReport(StockCallBackStatusEnum.FINISH, composeTask, composeTask.getTaskMsg());
                if(reporterResult.getItem1() != null) {
                    log.info("任务完成上报失败，组合任务ID：{}，错误信息：{}", composeTask.getTaskId(), reporterResult.getItem1());
                    dataRecorder.recordStockMsg(composeTask.getUpperTaskId(), composeTask.getVehicleNo(), "任务完成上报失败，错误信息：" + reporterResult.getItem1());
                    return;
                }
                log.info("任务完成上报成功，组合任务ID：{}，返回信息：{}", composeTask.getTaskId(), reporterResult.getItem2());
                boolean tran = transUtils.useTran(() -> {
                    AppStockComposeTaskBak composeTaskBak = new AppStockComposeTaskBak();
                    AppBeanUtils.copyProperties(composeTask, composeTaskBak);
                    stockComposeTaskBakService.insertThrowEx(composeTaskBak);
                    stockComposeTaskService.deleteWithTaskIdThrowEx(composeTask.getTaskId());
                    for (AppStockSingleTask stockSingleTask : stockSingleTasks) {
                        AppStockSingleTaskBak stockSingleTaskBak = new AppStockSingleTaskBak();
                        AppBeanUtils.copyProperties(stockSingleTask, stockSingleTaskBak);
                        stockSingleTaskBakService.insertThrowEx(stockSingleTaskBak);
                        stockSingleTaskService.deleteByTaskIdThrowEx(stockSingleTask.getTaskId());
                    }
                });
                log.info("任务完成，组合任务ID：{}，归档数据结果：{}", composeTask.getTaskId(), tran);
                return;
            }
            /* 取消任务 */
            if(composeTask.getTaskStatus().equals(StockComposeTaskStatusEnum.CANCEL.getCode())) {
                Tuple2<String, String> reporterResult = ReportStandard.stockTaskReport(StockCallBackStatusEnum.CANCEL, composeTask, composeTask.getTaskMsg());
                if(reporterResult.getItem1() != null) {
                    log.info("任务取消上报失败，组合任务ID：{}，错误信息：{}", composeTask.getTaskId(), reporterResult.getItem1());
                    dataRecorder.recordStockMsg(composeTask.getUpperTaskId(), composeTask.getVehicleNo(), "任务取消上报失败，错误信息：" + reporterResult.getItem1());
                    return;
                }
                log.info("任务取消上报成功，组合任务ID：{}，返回信息：{}", composeTask.getTaskId(), reporterResult.getItem2());
                boolean tran = transUtils.useTran(() -> {
                    AppStockComposeTaskBak composeTaskBak = new AppStockComposeTaskBak();
                    AppBeanUtils.copyProperties(composeTask, composeTaskBak);
                    stockComposeTaskBakService.insertThrowEx(composeTaskBak);
                    stockComposeTaskService.deleteWithTaskIdThrowEx(composeTask.getTaskId());
                    for (AppStockSingleTask stockSingleTask : stockSingleTasks) {
                        AppStockSingleTaskBak stockSingleTaskBak = new AppStockSingleTaskBak();
                        AppBeanUtils.copyProperties(stockSingleTask, stockSingleTaskBak);
                        stockSingleTaskBakService.insertThrowEx(stockSingleTaskBak);
                        stockSingleTaskService.deleteByTaskIdThrowEx(stockSingleTask.getTaskId());
                    }
                });
                log.info("任务取消，组合任务ID：{}，归档数据结果：{}", composeTask.getTaskId(), tran);
                return;
            }
        }
    }

    /**
     * 处理超时任务
     * @param timeoutTaskList 超时任务列表
     */
    private void resolveTimeoutStockTask(List<AppStockComposeTask> timeoutTaskList) {

    }

    /**
     * 处理异常任务
     * @param errorTaskList 异常任务列表
     */
    private void resolveErrorStockTask(List<AppStockComposeTask> errorTaskList) {

    }
}
