package com.cmvr.test.flow.runtime.engine;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.exceptions.ExceptionUtil;
import cn.hutool.core.util.ObjUtil;
import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson2.JSONObject;
import com.cmvr.common.exception.GlobalException;
import com.cmvr.test.enums.ActionEnum;
import com.cmvr.test.enums.RunModeEnum;
import com.cmvr.test.enums.TaskStatusEnum;
import com.cmvr.test.flow.context.TaskContext;
import com.cmvr.test.flow.context.TaskInstHolder;
import com.cmvr.test.model.domain.TeTaskInst;
import com.cmvr.test.model.dto.TeQueryTaskDetailDTO;
import com.cmvr.test.model.vo.TeDetectItemDeployFlowVO;
import com.cmvr.test.model.vo.TeTaskExecuteNormalVO;
import com.cmvr.test.model.vo.TeTaskExecuteProjectVO;
import com.cmvr.test.model.vo.TeTaskExecuteTrailVO;
import com.cmvr.test.service.ITeDetectionItemService;
import com.cmvr.test.service.ITeTaskInstService;
import com.cmvr.test.service.ITeTaskOrchestrationService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.List;

/**
 * 任务执行入口
 */
@Slf4j
@Service
@RequiredArgsConstructor
public class FlowTaskRuntimeEntry implements FlowTaskRuntimeService {

    private final ITeTaskOrchestrationService taskOrchestrationService;
    private final ITeTaskInstService taskInstService;
    private final ITeDetectionItemService detectionItemService;
    private final TaskInstHolder taskInstHolder;
    private final FlowTaskAsyncDispatcher flowTaskAsyncDispatcher;



    @Transactional(rollbackFor = Exception.class)
    public String executeTask(TeTaskExecuteNormalVO taskExecuteNormalVO) {
        return executeTaskInternal(
                taskExecuteNormalVO.getTerminalId(),
                taskExecuteNormalVO.getTaskId(),
                RunModeEnum.NORMAL,
                taskExecuteNormalVO.getRunParams(),
                taskExecuteNormalVO
        );
    }

    @Transactional(rollbackFor = Exception.class)
    public String executeTrialTask(TeTaskExecuteTrailVO taskExecuteTrailVO) {
        JSONObject runParams = taskExecuteTrailVO.getRunParams();
        String terminalId = taskExecuteTrailVO.getTerminalId();
        if (StrUtil.isEmpty(terminalId)) {
//            throw new GlobalException("终端ID不能为空");
        }
        if (terminalId != null && taskInstHolder.isTerminalLocked(terminalId)) {
            throw new GlobalException("当前终端正在执行其他任务，请稍后再试");
        }

        // 构建试运行任务定义（临时任务）
        String itemId = taskExecuteTrailVO.getItemId();

        TeDetectItemDeployFlowVO deployFlowVO = new TeDetectItemDeployFlowVO();
        deployFlowVO.setId(itemId);
        deployFlowVO.setFlowData(taskExecuteTrailVO.getFlowData());
        detectionItemService.deployFlow(deployFlowVO);

        String taskId = taskOrchestrationService.buildTrialTask(itemId);

        // 创建并保存任务实例
        TeTaskInst instance = createAndSaveTaskInstance(taskId, terminalId, RunModeEnum.TRIAL);
        String instId = instance.getId();

        try {
            // 构建任务详情（唯一检测项）
            TeQueryTaskDetailDTO teQueryTaskDetailDTO = new TeQueryTaskDetailDTO();
            teQueryTaskDetailDTO.setDetectItemId(itemId);
            teQueryTaskDetailDTO.setFlowData(taskExecuteTrailVO.getFlowData());
            teQueryTaskDetailDTO.setOrderNum(1);

            List<TeQueryTaskDetailDTO> details = CollUtil.newArrayList(teQueryTaskDetailDTO);

            // 注册上下文
            registerTaskContext(instId, taskId, terminalId, itemId, RunModeEnum.TRIAL, runParams);

            // 异步调度执行（与正式任务一致，只是模式为 TRIAL）
            flowTaskAsyncDispatcher.submit(instId, taskId, terminalId, RunModeEnum.TRIAL, details);

            return instId;
        } catch (Exception e) {
            taskInstHolder.markFailed(
                    instId, taskId, itemId,
                    null, null,
                    ActionEnum.NONE.getOperate(), ActionEnum.NONE.getAction(),
                    JSON.toJSONString(taskExecuteTrailVO),
                    "试运行异常：" + StrUtil.sub(ExceptionUtil.getMessage(e), 0, 480),
                    null);
            throw new GlobalException("试运行异常：" + e.getMessage());
        }
    }

    @Transactional(rollbackFor = Exception.class)
    public String executeProjectTask(TeTaskExecuteProjectVO taskExecuteProjectVO) {
        return executeTaskInternal(
                taskExecuteProjectVO.getTerminalId(),
                taskExecuteProjectVO.getProjectId(),
                RunModeEnum.VI_PROJECT,
                taskExecuteProjectVO.getRunParams(),
                taskExecuteProjectVO
        );
    }

    @Transactional(rollbackFor = Exception.class)
    public String executeTaskInternal(String terminalId, String taskId,
                                      RunModeEnum runMode, JSONObject runParams, Object originalVO) {
        if (StrUtil.isEmpty(terminalId)) {
//            throw new GlobalException("终端ID不能为空");
        }
        // 检查终端状态
        if (terminalId != null && taskInstHolder.isTerminalLocked(terminalId)) {
//            throw new GlobalException("当前终端正在执行其他任务，请稍后再试");
        }
        // 查询任务详情（检测项信息）
        List<TeQueryTaskDetailDTO> details = taskOrchestrationService.queryTaskDetail(taskId);
        int count = (int) details.stream().filter(dto -> ObjUtil.equals(dto.getIsDeploy(), "1")).count();
        if (count > 0) {
            throw new GlobalException("当前任务存在未发布的检测项!");
        }
        // 创建任务实例
        TeTaskInst instance = createAndSaveTaskInstance(taskId, terminalId, runMode);
        String instId = instance.getId();

        try {
            // 注册上下文
            registerTaskContext(instId, taskId, terminalId, null, runMode, runParams);

            // 异步提交执行
            flowTaskAsyncDispatcher.submit(instId, taskId, terminalId, runMode, details);
            return instId;
        } catch (Exception e) {
            taskInstHolder.markFailed(
                    instId, taskId, null, null, null,
                    ActionEnum.NONE.getOperate(), ActionEnum.NONE.getAction(),
                    JSON.toJSONString(originalVO),
                    "任务执行异常：" + StrUtil.sub(ExceptionUtil.getMessage(e), 0, 480),
                    null);
            throw new GlobalException("任务执行异常：" + e.getMessage());
        }
    }

    /**
     * 创建并保存任务实例
     */
    private TeTaskInst createAndSaveTaskInstance(String taskId, String terminalId, RunModeEnum runMode) {
        TeTaskInst instance = new TeTaskInst();
        instance.setTaskId(taskId);
        instance.setTerminalId(terminalId);
        instance.setRunMode(runMode.name());
        instance.setStatus(String.valueOf(TaskStatusEnum.RUNNING.getCode()));
        boolean save = taskInstService.save(instance);
        if (!save) {
            throw new GlobalException(StrUtil.format("创建 {} 任务实例失败，任务ID {}", runMode, taskId));
        }
        return instance;
    }

    /**
     * 注册上下文
     */
    private void registerTaskContext(String instId, String taskId, String terminalId,
                                     String itemId, RunModeEnum mode, JSONObject runParams) {
        TaskContext ctx = new TaskContext();
        ctx.setInstId(instId);
        ctx.setTaskId(taskId);
        ctx.setRunMode(mode);
        ctx.setTerminalId(terminalId);
        ctx.setItemId(itemId);
        ctx.setStatus(TaskStatusEnum.RUNNING);
        ctx.setTerminalLocked(true);
        ctx.setRunParams(runParams);

        taskInstHolder.register(ctx);
    }
}
