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

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.util.ObjUtil;
import com.alibaba.fastjson2.JSONObject;
import com.cmvr.test.enums.NodeTypeEnum;
import com.cmvr.test.flow.builder.FlowEdge;
import com.cmvr.test.flow.builder.FlowGraph;
import com.cmvr.test.flow.builder.FlowModelBuilder;
import com.cmvr.test.flow.builder.FlowNodeWrapper;
import com.cmvr.test.flow.builder.FlowParamDef;
import com.cmvr.test.flow.context.TaskContext;
import com.cmvr.test.flow.context.TaskInstHolder;
import com.cmvr.test.flow.context.TaskThreadRegistry;
import com.cmvr.test.flow.runtime.dispatcher.FlowNodeTypeDispatch;
import com.cmvr.test.flow.runtime.engine.support.FlowBranchEvaluator;
import com.cmvr.test.flow.runtime.engine.support.FlowExecutionChainBuilder;
import com.cmvr.test.flow.runtime.interceptor.FlowMsgPreInterceptor;
import com.cmvr.test.flow.runtime.message.TaskNodeExecuteContext;
import com.cmvr.test.flow.runtime.message.TaskNodeExecuteMessage;
import com.cmvr.test.flow.runtime.message.TaskNodeExecuteResult;
import com.cmvr.test.model.dto.TeQueryTaskDetailDTO;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.jetbrains.annotations.NotNull;
import org.springframework.stereotype.Component;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

@Slf4j
@Component
@RequiredArgsConstructor
public class FlowItemExecutor {

    private final FlowTaskScheduler flowTaskScheduler;
    private final List<FlowMsgPreInterceptor> interceptors;
    private final FlowNodeTypeDispatch dispatchNodeHandler;
    private final TaskInstHolder taskInstHolder;
    private final FlowExecutionChainBuilder chainBuilder;
    private final TaskThreadRegistry taskThreadRegistry;

    /**
     * 执行主流程（每个检测项调用一次）
     */
    public void executeGraph(TaskNodeExecuteMessage rootMessage,
                             TeQueryTaskDetailDTO item, Runnable onFinished) {

        FlowGraph graph = FlowModelBuilder.buildExecutableGraph(item.getFlowData());
        String startNodeId = graph.findStartNodeId();
        List<FlowParamDef> startInputDefs = graph.getStartInputParamsDefs();
        startInputDefs.clear();
        // 执行 start 节点（同步执行）
        NodeExecutor executor = node ->
                executeNode(graph, node, startNodeId, startInputDefs, rootMessage, onFinished, new ArrayList<>());

        executeNode(graph, graph.getStartNode(), startNodeId, startInputDefs, rootMessage, onFinished, new ArrayList<>());

        // 调度后续节点（并发）
        flowTaskScheduler.start(graph, taskInstHolder.getContext(rootMessage.getInstId()), executor, onFinished);
    }

    /**
     * 执行子图（子图循环）
     */
    public void executeSubGraph(FlowGraph subGraph,
                                TaskNodeExecuteMessage rootMessage,
                                Runnable onFinished,
                                List<Integer> iterations) {

        // 主图中开始节点的 inputParams
        List<FlowParamDef> startInputDefs = subGraph.getStartInputParamsDefs();

        // 子图的 start 节点
        FlowNodeWrapper subStartNode = subGraph.getInDegreeZeroNode();
        String subStartNodeId = subStartNode.getNodeId();

        NodeExecutor executor = node -> executeNode(
                subGraph, node, subStartNodeId, startInputDefs,
                rootMessage, onFinished, iterations
        );

        // 执行子图起始节点
        executeNode(subGraph, subStartNode, subStartNodeId, startInputDefs,
                rootMessage, onFinished, iterations);
        log.info("当前执行-子图");
        // 启动子图调度
        flowTaskScheduler.subStart(subGraph, taskInstHolder.getContext(rootMessage.getInstId()),
                executor, onFinished, iterations);
    }

    /**
     * 执行单个节点（核心调度逻辑）
     */
    public void executeNode(FlowGraph graph,
                            FlowNodeWrapper node,
                            String startNodeId,
                            List<FlowParamDef> startInputDefs,
                            TaskNodeExecuteMessage rootMessage,
                            Runnable onFinished,
                            List<Integer> iterations) {

        String instId = rootMessage.getInstId();
        String itemId = rootMessage.getItemId();
        String nodeId = node.getNodeId();
        String nodeName = node.getNodeName();
        log.info("当前执行的是 {} 节点，迭代路径={}", node.getNodeName(), iterations);

        //注册当前线程
        registerThread(graph, node, startNodeId, startInputDefs, rootMessage, onFinished, iterations, instId, itemId, nodeId);

        try {
            // 创建带上下文的执行消息
            TaskNodeExecuteMessage message = buildTaskNodeExecuteMsg(
                    graph, node, rootMessage, nodeId, nodeName, iterations
            );

            // 执行责任链
            TaskNodeExecuteResult result = chainBuilder.build(interceptors, dispatchNodeHandler).apply(message);

            if (ObjUtil.isEmpty(result) || !result.isSuccess()) {
//                log.warn("节点执行失败，中断调度：nodeId={}, status={}", nodeId, result != null ? result.isSuccess() : "null");
                return;
            }

            // 分支节点处理
            if (node.getNodeType() == NodeTypeEnum.BRANCH) {
                postHandleBranchNode(taskInstHolder.getContext(rootMessage.getInstId()), graph, node, startNodeId, startInputDefs,
                        rootMessage, onFinished, iterations, nodeId, message.getInputParams(), message);
                return;
            }

            // END 节点 or 子图结束
            if (node.getNodeType() == NodeTypeEnum.END || node.getNodeType() == NodeTypeEnum.SUB_END || graph.isSubGraphEndNode(nodeId)) {
                try {
                    log.info("{} 节点执行，释放线程", node.getNodeType());
                    onFinished.run();
                } catch (Exception e) {
                    log.error("onFinished 回调异常", e);
                }
            }

            // 通知调度器继续调度后继节点
            flowTaskScheduler.markCompleted(
                    message.getInstId(), nodeId, graph,
                    n -> executeNode(graph, n, startNodeId, startInputDefs, rootMessage, onFinished, iterations),
                    iterations
            );
        } finally {
            // 如果不是暂停全中断
            TaskContext ctx = taskInstHolder.getContext(instId);
            if (ctx == null || !ctx.isPaused()) {
                taskThreadRegistry.unregisterNodeContext(instId, itemId, nodeId);
            }
        }
    }

    @NotNull
    private static TaskNodeExecuteMessage buildTaskNodeExecuteMsg(FlowGraph graph, FlowNodeWrapper node,
                                                                  TaskNodeExecuteMessage rootMessage, String nodeId, String nodeName,
                                                                  List<Integer> iterations) {
        TaskNodeExecuteMessage message = new TaskNodeExecuteMessage();
        BeanUtil.copyProperties(rootMessage, message);
        message.setNodeId(nodeId);
        message.setNodeType(node.getNodeType().name());
        message.setAction(node.getAction());
        message.setNodeName(nodeName);
//        message.setInputParams(inputParams);
        message.setGraph(graph);
        // 只设置 iterations
        message.setIterations(new ArrayList<>(iterations));

        // loopNum 不在这里计算，而是由 FlowLoopNodeHandler / resume 显式写入
        // 如果 rootMessage 里已经带了 loopNum，就沿用它
        message.setLoopNum(rootMessage.getLoopNum());

        message.setLoopArray(rootMessage.getLoopArray());
        return message;
    }

    private void postHandleBranchNode(TaskContext taskContext, FlowGraph graph, FlowNodeWrapper node, String startNodeId,
                                      List<FlowParamDef> startInputDefs, TaskNodeExecuteMessage rootMessage, Runnable onFinished,
                                      List<Integer> iterations, String nodeId, JSONObject inputParams, TaskNodeExecuteMessage message) {
        String matchedAnchorId = FlowBranchEvaluator.evaluate(taskContext, iterations,nodeId, node.getBranchConditions(), inputParams);
        FlowEdge matchedEdge = graph.getEdgeByFromAnchorId(matchedAnchorId);

        if (matchedEdge == null) {
            log.warn("未找到匹配的分支出边，anchorId={}, nodeId={}", matchedAnchorId, nodeId);
            return;
        }

        // 移除未命中的路径
        List<FlowEdge> allOutEdges = new ArrayList<>(graph.getSuccessors().getOrDefault(nodeId, Collections.emptyList()));
        for (FlowEdge edge : allOutEdges) {
            if (!edge.equals(matchedEdge)) {
                // 先删边
                graph.removeEdge(edge);

                // 再尝试删子路径（只有当目标节点没有其他前驱时才删）
                List<FlowEdge> predecessorsList = graph.getPredecessors().getOrDefault(edge.getTo(), Collections.emptyList());
                if (predecessorsList.isEmpty()) {
                    graph.removePathFrom(edge.getTo());
                }
            }
        }

        // 直接调度命中节点
        flowTaskScheduler.scheduleDirectly(
                message.getInstId(),
                matchedEdge.getTo(),
                graph,
                n -> executeNode(graph, n, startNodeId, startInputDefs, rootMessage, onFinished, iterations),
                iterations
        );
    }

    private void registerThread(FlowGraph graph, FlowNodeWrapper node, String startNodeId, List<FlowParamDef> startInputDefs,
                                TaskNodeExecuteMessage rootMessage, Runnable onFinished, List<Integer> iterations, String instId, String itemId, String nodeId) {
        TaskNodeExecuteContext nodeExecuteContext = new TaskNodeExecuteContext();
        nodeExecuteContext.setThread(Thread.currentThread());
        nodeExecuteContext.setGraph(graph);
        nodeExecuteContext.setStartNodeId(startNodeId);
        nodeExecuteContext.setStartInputDefs(startInputDefs);
        nodeExecuteContext.setNode(node);
        nodeExecuteContext.setOnFinished(onFinished);
        nodeExecuteContext.setRootMessage(rootMessage);
//        nodeExecuteContext.setLoopIteration(loopIteration);
        nodeExecuteContext.setIterations(new ArrayList<>(iterations));
        taskThreadRegistry.registerNodeContext(instId, itemId, nodeId, nodeExecuteContext);
    }

    /**
     * 节点执行接口（用于调度器回调）
     */
    @FunctionalInterface
    public interface NodeExecutor {
        void execute(FlowNodeWrapper node);
    }
}
