package com.cmvr.test.flow.builder;

import com.cmvr.test.enums.NodeTypeEnum;
import lombok.Data;

import java.util.ArrayList;
import java.util.Collections;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.locks.ReadWriteLock;
import java.util.concurrent.locks.ReentrantReadWriteLock;
import java.util.stream.Collectors;

/**
 * 检测项流程执行图（DAG）（支持条件、并发、跳转等）
 */
@Data
public class FlowGraph {

    /**
     * 节点 ID → NodeWrapper
     */
    private Map<String, FlowNodeWrapper> nodeMap = new LinkedHashMap<>();

    /**
     * 节点 ID → 出边集合
     */
    private Map<String, List<FlowEdge>> successors = new ConcurrentHashMap<>();

    /**
     * 节点 ID → 入边集合
     */
    private Map<String, List<FlowEdge>> predecessors = new ConcurrentHashMap<>();

    /**
     * 除start节点外的参数集合
     */
    private Map<String, List<FlowParamDef>> nodeParamsDefs = new ConcurrentHashMap<>();

    /**
     * start节点参数集合
     */
    private List<FlowParamDef> startInputParamsDefs = new ArrayList<>();

    // 是否跳出循环
    private volatile boolean stopLoop = false;

    /**
     * 是否为子图
     */
    private boolean isSub = false;

    /**
     * 内部读写锁，保障读写时不互打
     */
    private final ReadWriteLock lock = new ReentrantReadWriteLock();

    /**
     * 添加边（默认同步、无条件）
     */
    public void addEdge(String from, String to, String fromAnchorId) {
        addEdge(new FlowEdge(from, to, fromAnchorId, null));
    }

    /**
     * 添加边对象
     */
    public void addEdge(FlowEdge edge) {
        lock.writeLock().lock();
        try {
            successors.computeIfAbsent(edge.getFrom(), k -> Collections.synchronizedList(new ArrayList<>())).add(edge);
            predecessors.computeIfAbsent(edge.getTo(), k -> Collections.synchronizedList(new ArrayList<>())).add(edge);
        } finally {
            lock.writeLock().unlock();
        }
    }

    /**
     * 查找起始节点（START 类型）
     */
    public String findStartNodeId() {
        lock.readLock().lock();
        try {
            return nodeMap.values().stream()
                    .filter(n -> n.getNodeType() == NodeTypeEnum.START)
                    .map(FlowNodeWrapper::getNodeId)
                    .findFirst()
                    .orElseThrow(() -> new RuntimeException("未找到开始节点"));
        } finally {
            lock.readLock().unlock();
        }
    }

    /**
     * 查找子图起始节点（SUB_START 类型）
     */
    public FlowNodeWrapper findSubStartNodeId() {
        lock.readLock().lock();
        try {
            return nodeMap.values().stream()
                    .filter(n -> n.getNodeType() == NodeTypeEnum.SUB_START)
//                    .map(FlowNodeWrapper::getNodeId)
                    .findFirst()
                    .orElseThrow(() -> new RuntimeException("未找到开始节点"));
        } finally {
            lock.readLock().unlock();
        }
    }

    /**
     * 获取子图中起始节点（入度为0）
     */
    public FlowNodeWrapper getInDegreeZeroNode() {
        lock.readLock().lock();
        try {
            for (FlowNodeWrapper node : nodeMap.values()) {
                List<FlowEdge> flowEdges = predecessors.get(node.getNodeId());
                if (flowEdges == null || flowEdges.isEmpty()) {
                    return node;
                }
            }
            return null;
        } finally {
            lock.readLock().unlock();
        }
    }

    /**
     * 判断是否为子图中的结束节点（出度为0）
     */
    public boolean isSubGraphEndNode(String nodeId) {
        lock.readLock().lock();
        try {
            if (!this.isSub()) {
                return false;
            }
            List<String> nextNodes = this.getNextNodes(nodeId);
            return nextNodes == null || nextNodes.isEmpty();
        } finally {
            lock.readLock().unlock();
        }
    }

    /**
     * 获取当前节点的所有出边
     */
    public List<FlowEdge> getOutgoingEdges(String nodeId) {
        lock.readLock().lock();
        try {
            return successors.getOrDefault(nodeId, Collections.emptyList());
        } finally {
            lock.readLock().unlock();
        }
    }

    /**
     * 获取当前节点的所有后继节点 ID（无条件过滤）
     */
    public List<String> getNextNodes(String nodeId) {
        List<FlowEdge> edges = getOutgoingEdges(nodeId);
        List<String> list = new ArrayList<>();
        for (FlowEdge edge : edges) {
            if (edge.getCondition() == null) {
                list.add(edge.getTo());
            }
        }
        return list;
    }

    /**
     * 获取开始节点对象
     */
    public FlowNodeWrapper getStartNode() {
        String id = findStartNodeId();
        return getNode(id);
    }

    /**
     * 获取节点对象
     */
    public FlowNodeWrapper getNode(String nodeId) {
        lock.readLock().lock();
        try {
            return nodeMap.get(nodeId);
        } finally {
            lock.readLock().unlock();
        }
    }

    /**
     * 根据 from → to 查找边对象
     */
    public FlowEdge getEdge(String from, String to) {
        List<FlowEdge> edges = getOutgoingEdges(from);
        for (FlowEdge edge : edges) {
            if (edge.getTo().equals(to)) {
                return edge;
            }
        }
        return null;
    }

    /**
     * 根据 fromAnchorId 查找边对象
     */
    public FlowEdge getEdgeByFromAnchorId(String fromAnchorId) {
        lock.readLock().lock();
        try {
            Set<FlowEdge> edges = successors.values().stream()
                    .flatMap(List::stream)
                    .collect(Collectors.toSet());
            for (FlowEdge edge : edges) {
                if (edge.getFromAnchorId().equals(fromAnchorId)) {
                    return edge;
                }
            }
            return null;
        } finally {
            lock.readLock().unlock();
        }
    }

    public void removePathFrom(String nodeId) {
        lock.writeLock().lock();
        try {
            List<FlowEdge> outEdges = successors.getOrDefault(nodeId, Collections.emptyList());
            for (FlowEdge edge : new ArrayList<>(outEdges)) {
                String targetNodeId = edge.getTo();

                // 先删边
                removeEdge(edge);

                // 只有目标节点没有其他前驱时才递归
                List<FlowEdge> predecessorsList = predecessors.getOrDefault(targetNodeId, Collections.emptyList());
                if (predecessorsList.isEmpty()) {
                    removePathFrom(targetNodeId);
                }
            }

            // 最后判断是否孤立再删节点
            removeNodeIfIsolated(nodeId);
        } finally {
            lock.writeLock().unlock();
        }
    }

    public void removeEdge(FlowEdge edge) {
        lock.writeLock().lock();
        try {
            List<FlowEdge> outList = successors.get(edge.getFrom());
            if (outList != null) {
                outList.removeIf(e -> e.equals(edge));
                if (outList.isEmpty()) {
                    successors.remove(edge.getFrom());
                }
            }

            List<FlowEdge> inList = predecessors.get(edge.getTo());
            if (inList != null) {
                inList.removeIf(e -> e.equals(edge));
                if (inList.isEmpty()) {
                    predecessors.remove(edge.getTo());
                }
            }
        } finally {
            lock.writeLock().unlock();
        }
    }

    public void removeNodeIfIsolated(String nodeId) {
        lock.writeLock().lock();
        try {
            boolean hasIn = predecessors.containsKey(nodeId) && !predecessors.get(nodeId).isEmpty();
            boolean hasOut = successors.containsKey(nodeId) && !successors.get(nodeId).isEmpty();
            if (!hasIn && !hasOut) {
                nodeMap.remove(nodeId);
            }
        } finally {
            lock.writeLock().unlock();
        }
    }

    /**
     * 所有节点 ID
     */
    public List<String> allNodeIds() {
        lock.readLock().lock();
        try {
            return new ArrayList<>(nodeMap.keySet());
        } finally {
            lock.readLock().unlock();
        }
    }

    /**
     * 是否跳出循环（用于 STOP_LOOP 控制节点）
     */
    public boolean isBreakLoop() {
        return stopLoop;
    }
}
