package cd.casic.ci.process.engine.dispatcher.impl;

import cd.casic.ci.process.engine.constant.PipelineBehaviorConstant;
import cd.casic.ci.process.engine.dispatcher.BaseDispatcher;
import cd.casic.ci.process.engine.enums.ContextStateEnum;
import cd.casic.ci.process.engine.manager.RunContextManager;
import cd.casic.ci.process.engine.message.TaskRunMessage;
import cd.casic.ci.process.engine.runContext.BaseRunContext;
import cd.casic.ci.process.engine.runContext.SecondStageRunContext;
import cd.casic.ci.process.engine.runContext.TaskRunContext;
import cd.casic.ci.process.process.dataObject.base.PipBaseElement;
import cd.casic.ci.process.process.dataObject.pipeline.PipPipeline;
import cd.casic.ci.process.process.dataObject.stage.PipStage;
import cd.casic.ci.process.process.dataObject.task.PipTask;
import cd.casic.framework.mq.redis.core.RedisMQTemplate;
import lombok.extern.slf4j.Slf4j;

import java.time.LocalDateTime;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.atomic.AtomicInteger;
@Slf4j
public class SerialDispatcher implements BaseDispatcher {
    private SecondStageRunContext stageRunContext;
    private List<PipTask> taskList;
    private CountDownLatch latch;
    private String triggerModel;
    private RedisMQTemplate redisMQTemplate;
    private RunContextManager contextManager;

    public SerialDispatcher(SecondStageRunContext stageRunContext, CountDownLatch latch,RunContextManager contextManager,RedisMQTemplate redisMQTemplate) {
        this.stageRunContext = stageRunContext;
        PipBaseElement contextDef = stageRunContext.getContextDef();
        if (contextDef instanceof PipStage secondStage) {
            this.triggerModel = secondStage.getTriggerMode();
            this.taskList = secondStage.getTaskValues();
        }
        this.latch = latch;
        this.redisMQTemplate = redisMQTemplate;
        this.contextManager = contextManager;
    }

    @Override
    public void dispatch() {
        for (PipTask pipTask : taskList) {
            TaskRunContext taskRunContext = null;
            Map<String, Object> globalVariables = stageRunContext.getGlobalVariables();
            Object fromError = globalVariables.get(PipelineBehaviorConstant.PIPELINE_EXECUTE_FROM_ERROR);
            if (!Boolean.TRUE.equals(fromError)) {
                // 注册taskContext，且发送消息至消息队列给work执行, 如果需要则传入参数
                taskRunContext = new TaskRunContext(pipTask,stageRunContext,new HashMap<>());
                contextManager.contextRegister(taskRunContext);
            } else {
                BaseRunContext context = contextManager.getContext(pipTask.getId());
                if (context != null) {
                    taskRunContext= (TaskRunContext) context;
                    context.setContextDef(pipTask);
                    // 之前错误的节点从错误出执行的时候会变成 这个新的状态
                    if (ContextStateEnum.ERROR_EXECUTE_READY.getCode().equals(context.getState().get())) {
                        context.setEndTime(null);
                    }
                } else {
                    // 防止运行停止以后添加节点,以及到达之前未执行的节点 ,todo 删除节点的同时也要删除上下文
                    taskRunContext = new TaskRunContext(pipTask,stageRunContext,new HashMap<>());
                    contextManager.contextRegister(taskRunContext);
                }
            }
            taskRunContext.changeContextState(ContextStateEnum.READY);
            TaskRunMessage taskRunMessage = new TaskRunMessage(pipTask);
            redisMQTemplate.send(taskRunMessage);
            //监听当前taskContext状态变成执行成功或者执行失败(worker当中改变状态为运行中、执行成功、执行失败)
            AtomicInteger state = taskRunContext.getState();
            // 如果不为正常执行成功就暂时阻塞直到有状态更改
            while (state.get() != ContextStateEnum.HAPPY_ENDING.getCode()
                    && state.get() != ContextStateEnum.BAD_ENDING.getCode()
                    && state.get() != ContextStateEnum.SKIP_TO.getCode()
            ) {
//                Thread.sleep(1000L);
                taskRunContext.pause();
            }
            //
            if (state.get()== ContextStateEnum.BAD_ENDING.getCode()) {
                log.error("串行执行停止");
                break;
            }
        }
    }

    @Override
    public void run() {
        try {
            // TODO 检测触发方式如果需要手动触发，挂起当前stage，等待父级执行相应操作
            // TODO 看看需要内存入库还是忽略掉当前执行，进行入库（countDown放行）
//            stageRunContext.callParentChange();
            dispatch();
        } catch (Exception e) {
//            throw new RuntimeException(e);
            // TODO 当前stage标记为失败等待父context发现并处理
        }
        latch.countDown();
    }
}
