package com.cmvr.test.flow.builder;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.ObjUtil;
import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson2.JSONArray;
import com.alibaba.fastjson2.JSONObject;
import com.cmvr.common.exception.GlobalException;
import com.cmvr.test.enums.ActionEnum;
import com.cmvr.test.enums.BranchConditionOpEnum;
import com.cmvr.test.enums.NodeTypeEnum;
import com.cmvr.test.enums.ParamScope;

import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;

/**
 * 构建任务执行图（支持主流程 + 子图 + 循环）
 */
public class FlowModelBuilder {

    /**
     * 构建任务执行图（DAG）
     */
    public static FlowGraph buildExecutableGraph(String flowJson) {
        JSONObject flow = JSON.parseObject(flowJson);
        JSONArray nodeArray = flow.getJSONArray("nodes");
        JSONArray edgeArray = flow.getJSONArray("edges");

        FlowGraph graph = new FlowGraph();

        // 解析节点列表
        Map<String, FlowNodeWrapper> nodeMap = parseNodes(nodeArray);

        // 解析边并写入图
        parseEdges(graph, edgeArray);

        // 处理循环节点的子节点和循环参数
        List<String> nodesToRemove = bindLoopChildrenAndParams(nodeMap);

        // 构建子图结构
        processSubGraphs(nodeMap, graph);

        // 设置全量参数
        setParams(nodeMap, graph);

        // 将子图中的节点从主图移除
        removeChildNodesFromMainGraph(graph, nodeMap, nodesToRemove);

        // 设置主图节点映射
        graph.setNodeMap(nodeMap);

        return graph;
    }

    private static void setParams(Map<String, FlowNodeWrapper> nodeMap, FlowGraph graph) {
        Map<String, List<FlowParamDef>> nodeParams = new LinkedHashMap<>();
        for (Map.Entry<String, FlowNodeWrapper> entry : nodeMap.entrySet()) {
            FlowNodeWrapper node = entry.getValue();
            String nodeId = entry.getKey();
            if (node.getNodeType().equals(NodeTypeEnum.START)) {
                graph.setStartInputParamsDefs(node.getInputParams());
            }
            nodeParams.put(nodeId, node.getNodeParams());
        }
        graph.setNodeParamsDefs(nodeParams);
    }

    /**
     * 解析节点数组为节点映射
     */
    private static Map<String, FlowNodeWrapper> parseNodes(JSONArray nodeArray) {
        Map<String, FlowNodeWrapper> nodeMap = new HashMap<>();
        for (int i = 0; i < nodeArray.size(); i++) {
            JSONObject nodeJson = nodeArray.getJSONObject(i);
            String actionStr = nodeJson.getJSONObject("properties").getString("action");
            if (actionStr.equalsIgnoreCase(ActionEnum.NONE.getAction())) {
                // 跳过框选节点
                continue;
            }
            FlowNodeWrapper wrapper = parseNode(nodeJson);  // 解析单个节点
            nodeMap.put(wrapper.getNodeId(), wrapper);
        }
        return nodeMap;
    }

    /**
     * 解析边数组为图中边结构
     */
    private static void parseEdges(FlowGraph graph, JSONArray edgeArray) {
        for (int i = 0; i < edgeArray.size(); i++) {
            JSONObject edgeJson = edgeArray.getJSONObject(i);

            String from = edgeJson.getString("sourceNodeId");
            String to = edgeJson.getString("targetNodeId");
            String fromAnchorId = edgeJson.getString("sourceAnchorId");
            String condition = edgeJson.getString("condition");

            FlowEdge edge = new FlowEdge(from, to,fromAnchorId, condition);
            graph.addEdge(edge);
        }
    }

    /**
     * 绑定循环节点中的子节点和循环参数
     */
    private static List<String> bindLoopChildrenAndParams(Map<String, FlowNodeWrapper> nodeMap) {
        List<String> toRemove = new ArrayList<>();
        for (FlowNodeWrapper wrapper : nodeMap.values()) {
            if (wrapper.getNodeType() == NodeTypeEnum.LOOP) {
                // 获取循环子节点
                JSONArray children = wrapper.getRawProperties().getJSONArray("children");
                List<FlowNodeWrapper> childList = new ArrayList<>();
                for (int i = 0; i < children.size(); i++) {
                    String childNodeId = children.getString(i);
                    FlowNodeWrapper child = nodeMap.get(childNodeId);
                    if (child != null) {
                        childList.add(child);
                        toRemove.add(childNodeId); // 标记后续移除
                    }
                }
                wrapper.setChildNodes(childList);
            }
        }
        return toRemove;
    }

    /**
     * 处理所有子流程图（循环子图）
     */
    private static void processSubGraphs(Map<String, FlowNodeWrapper> nodeMap, FlowGraph graph) {
        for (FlowNodeWrapper wrapper : nodeMap.values()) {
            if (wrapper.getNodeType() == NodeTypeEnum.LOOP) {
                FlowGraph subGraph = new FlowGraph();
                wrapper.setSubGraph(subGraph);

                List<FlowNodeWrapper> children = wrapper.getChildNodes();
                for (FlowNodeWrapper child : children) {
                    subGraph.getNodeMap().put(child.getNodeId(), child);  // 添加子节点
                }

                // 添加子图内部的边（来源于主图）
                for (FlowNodeWrapper child : children) {
                    List<FlowEdge> outEdges = graph.getSuccessors().getOrDefault(child.getNodeId(), Collections.emptyList());
                    for (FlowEdge edge : outEdges) {
                        if (subGraph.getNodeMap().containsKey(edge.getTo())) {
                            subGraph.addEdge(edge);
                        }
                    }
                }
            }
        }
    }

    /**
     * 从主图中移除子流程节点（最后执行）
     */
    private static void removeChildNodesFromMainGraph(FlowGraph graph, Map<String, FlowNodeWrapper> nodeMap, List<String> toRemove) {
        for (String nodeId : toRemove) {
            nodeMap.remove(nodeId);
            graph.getSuccessors().remove(nodeId);
            graph.getPredecessors().remove(nodeId);
        }
    }
    /**
     * 解析单个节点对象为包装类
     */
    private static FlowNodeWrapper parseNode(JSONObject nodeJson) {
        FlowNodeWrapper wrapper = new FlowNodeWrapper();
        wrapper.setNodeId(nodeJson.getString("id"));

        JSONObject props = nodeJson.getJSONObject("properties");
        wrapper.setNodeName(props.getString("name"));

        // 设置动作类型
        String actionStr = props.getString("action");
        ActionEnum action = ActionEnum.fromAction(actionStr);
        if (ObjUtil.isEmpty(action)) {
            throw new IllegalArgumentException("无法识别的action：" + actionStr);
        }
        wrapper.setAction(action);

        // 设置节点类型
        NodeTypeEnum nodeType = resolveNodeType(nodeJson.getString("type"));
        wrapper.setNodeType(nodeType);

        // 补充循环节点的子节点信息
        if (nodeType == NodeTypeEnum.LOOP) {
            props.put("children", nodeJson.getJSONArray("children"));
        }

        wrapper.setRawProperties(props);

        // 设置参数
        wrapper.setInputParams(parseParamsWithScope(props.getJSONArray("inputParams"), ParamScope.INPUT));
        wrapper.setNodeParams(parseParamsWithScope(props.getJSONArray("nodeParams"), ParamScope.NODE));

        // 解析分支条件逻辑
        parseBranch(nodeType, props, wrapper);

        return wrapper;
    }

    /**
     * 解析分支条件逻辑
     */
    private static void parseBranch(NodeTypeEnum nodeType, JSONObject props, FlowNodeWrapper wrapper) {
        if (nodeType == NodeTypeEnum.BRANCH && props.containsKey("nodeParams")) {
            JSONArray branchArray = props.getJSONArray("nodeParams");
            List<FlowBranchConditionGroup> branchList = new ArrayList<>();

            for (int i = 0; i < branchArray.size(); i++) {
                JSONObject branchObj = branchArray.getJSONObject(i);

                FlowBranchConditionGroup group = new FlowBranchConditionGroup();
                group.setId(branchObj.getString("id"));
                group.setWithOr(branchObj.getString("withOr"));

                JSONArray exprArray = branchObj.getJSONArray("list");
                List<FlowBranchConditionGroup.ConditionExpression> expressions = new ArrayList<>();

                for (int j = 0; j < exprArray.size(); j++) {
                    JSONObject exprObj = exprArray.getJSONObject(j);
                    FlowBranchConditionGroup.ConditionExpression expr = new FlowBranchConditionGroup.ConditionExpression();

                    // 解析左值：参数名
                    String nameType = exprObj.getString("nameType");
                    expr.setNameType(nameType);
                    if ("quote".equalsIgnoreCase(nameType)) {
                        List<String> nameQuotePath = exprObj.getJSONArray("nameQuote").toJavaList(String.class);
                        expr.setNameQuotePath(nameQuotePath);
                        // 提前设置 name 字段为路径最后一个
                        if (!nameQuotePath.isEmpty()) {
                            expr.setName(nameQuotePath.get(nameQuotePath.size() - 1));
                        }
                    } else if ("input".equalsIgnoreCase(nameType)) {
                        expr.setName(exprObj.getString("name"));
                    } else {
                        throw new GlobalException("分支节点参数解析出错，id:" + group.getId());
                    }

                    // 解析右值：值或引用
                    String valueType = exprObj.getString("type");
                    expr.setValueType(valueType);
                    if ("quote".equalsIgnoreCase(valueType)) {
                        expr.setQuotePath(exprObj.getJSONArray("quote").toJavaList(String.class));
                    } else {
                        expr.setInput(exprObj.getString("input"));
                    }

                    // 运算符
                    expr.setCondition(BranchConditionOpEnum.fromValue(exprObj.getString("condition")));
                    expressions.add(expr);
                }

                group.setExpressions(expressions);
                branchList.add(group);
            }

            wrapper.setBranchConditions(branchList);
        }
    }

    /**
     * 解析前端 type 转换为 NodeTypeEnum
     */
    private static NodeTypeEnum resolveNodeType(String type) {
        switch (type.toLowerCase()) {
            case "start":
                return NodeTypeEnum.START;
            case "substart":
                return NodeTypeEnum.SUB_START;
            case "end":
                return NodeTypeEnum.END;
            case "subend":
                return NodeTypeEnum.SUB_END;
            case "branch":
                return NodeTypeEnum.BRANCH;
            case "loop":
                return NodeTypeEnum.LOOP;
            case "stoploop":
                return NodeTypeEnum.STOP_LOOP;
            case "sleep":
                return NodeTypeEnum.SLEEP;
            case "http":
                return NodeTypeEnum.HTTP;
            case "code":
                return NodeTypeEnum.CODE;
            case "currentloop":
                return NodeTypeEnum.GET_CURRENT_OBJECT;
            default:
                return NodeTypeEnum.FUNCTION;
        }
    }

    /**
     * 解析带有 Scope 的参数列表
     */
    private static List<FlowParamDef> parseParamsWithScope(JSONArray array, ParamScope scope) {
        if (array == null) return new ArrayList<>();
        List<FlowParamDef> result = new ArrayList<>();
        for (int i = 0; i < array.size(); i++) {
            FlowParamDef def = array.getObject(i, FlowParamDef.class);
            def.setScope(scope);

            // 递归处理 children
            if (CollUtil.isNotEmpty(def.getChildren())) {
                List<FlowParamDef> children = parseParamsWithScope(new JSONArray(def.getChildren()), scope);
                def.setChildren(children);
            }

            result.add(def);
        }
        return result;
    }
}
