//! DAG（有向无环图）定义与拓扑排序

use std::collections::{HashMap, HashSet, VecDeque};

use df_types::error::Result;
use df_types::types::NodeId;

use crate::node::Node;

/// 图的边：从 source 到 target
#[derive(Debug, Clone)]
pub struct Edge {
    pub source: NodeId,
    pub target: NodeId,
    /// 边的条件表达式（可选）
    pub condition: Option<String>,
}

/// DAG 结构
pub struct Dag {
    /// 节点集合
    pub nodes: HashMap<NodeId, Box<dyn Node>>,
    /// 边集合
    pub edges: Vec<Edge>,
    /// 节点级配置（DagDef.nodes[id].config 提取自 build_dag，run 时与全局 config deep_merge）
    ///
    /// 语义：节点级覆盖全局级。DagExecutor 构造 NodeContext 时执行
    /// `deep_merge(initial_config, node_configs[id])`，节点定义里写的同名 key 优先于
    /// run_workflow 传入的全局 config。
    pub node_configs: HashMap<NodeId, serde_json::Value>,
}

impl Dag {
    /// 创建空 DAG
    pub fn new() -> Self {
        Self {
            nodes: HashMap::new(),
            edges: Vec::new(),
            node_configs: HashMap::new(),
        }
    }

    /// 添加节点
    pub fn add_node(&mut self, id: NodeId, node: Box<dyn Node>) {
        self.nodes.insert(id, node);
    }

    /// 添加节点（附带节点级配置）
    ///
    /// 节点级配置在 DagExecutor 构造 NodeContext 时覆盖全局 config（deep_merge）。
    pub fn add_node_with_config(
        &mut self,
        id: NodeId,
        node: Box<dyn Node>,
        config: serde_json::Value,
    ) {
        self.nodes.insert(id.clone(), node);
        self.node_configs.insert(id, config);
    }

    /// 添加边
    pub fn add_edge(&mut self, source: NodeId, target: NodeId) {
        self.edges.push(Edge {
            source,
            target,
            condition: None,
        });
    }

    /// 添加带条件的边
    pub fn add_edge_with_condition(
        &mut self,
        source: NodeId,
        target: NodeId,
        condition: String,
    ) {
        self.edges.push(Edge {
            source,
            target,
            condition: Some(condition),
        });
    }

    /// 拓扑排序 — 返回按执行顺序排列的节点 ID 层级
    ///
    /// 返回 Vec<Vec<NodeId>>，每层内的节点可以并行执行。
    ///
    /// 复杂度：O(V+E)。一次性遍历边构建邻接索引（出边表）与入度表，
    /// BFS 分层只走索引查询（每条边仅被访问一次），不再为每个节点全表扫描边集合。
    pub fn topological_layers(&self) -> Result<Vec<Vec<NodeId>>> {
        let node_ids: HashSet<NodeId> = self.nodes.keys().cloned().collect();
        let mut in_degree: HashMap<NodeId, usize> = HashMap::new();
        // 邻接出边表：source → 直接后继列表（仅含两端均在 nodes 内的有效边）
        let mut adjacency_out: HashMap<NodeId, Vec<NodeId>> = HashMap::new();

        // 初始化入度（确保每个节点都有表项，便于后续 O(1) 修改）
        for id in &node_ids {
            in_degree.insert(id.clone(), 0);
        }
        // 单次 O(E) 遍历：同时构建入度表与出边表
        for edge in &self.edges {
            // 仅收录两端均为已注册节点的边，跳过野节点
            if node_ids.contains(&edge.source) && node_ids.contains(&edge.target) {
                // safe: edge.target 已在 node_ids 中（上一行 contains 守卫），而 in_degree
                // 对每个 node_id 都插入了表项（line 97-99 初始化），故 get_mut 必命中
                *in_degree.get_mut(&edge.target).unwrap() += 1;
                adjacency_out
                    .entry(edge.source.clone())
                    .or_default()
                    .push(edge.target.clone());
            }
        }

        // BFS 分层
        let mut layers = Vec::new();
        let mut queue: VecDeque<NodeId> = in_degree
            .iter()
            .filter(|(_, &deg)| deg == 0)
            .map(|(id, _)| id.clone())
            .collect();

        let mut processed = 0usize;
        while !queue.is_empty() {
            let mut layer: Vec<NodeId> = Vec::new();
            let layer_size = queue.len();
            for _ in 0..layer_size {
                if let Some(id) = queue.pop_front() {
                    layer.push(id.clone());
                    // 出边已索引，O(出度) 遍历而非 O(E) 全表扫描
                    if let Some(succs) = adjacency_out.get(&id) {
                        for succ in succs {
                            // safe: succ 来自 adjacency_out，其元素均为通过 line 103 contains 守卫
                            // 的 edge.target（line 108 push），而 in_degree 覆盖所有 node_id（line 97-99），
                            // 故 succ 必在 in_degree 表内，get_mut 必命中
                            let deg = in_degree.get_mut(succ).unwrap();
                            *deg -= 1;
                            if *deg == 0 {
                                queue.push_back(succ.clone());
                            }
                        }
                    }
                    processed += 1;
                }
            }
            layers.push(layer);
        }

        if processed != node_ids.len() {
            return Err(df_types::error::Error::Workflow(
                "DAG 中存在环，无法进行拓扑排序".to_string(),
            ));
        }

        Ok(layers)
    }
}

impl Default for Dag {
    fn default() -> Self {
        Self::new()
    }
}

/// 深度合并两个 JSON 值：节点级 `node` 覆盖全局级 `global`。
///
/// 规则：
/// - 两端均为 Object：递归合并（同 key 时节点级覆盖全局级，新增 key 各自保留）。
/// - 非 Object/Null 两端：节点级直接覆盖全局级。
/// - 节点级为 `Null` 时跳过（保留全局配置），对应语义「节点未指定该配置」。
///   若调用方希望「显式置空」，应在构造 Dag 时不写入该 key（node_configs 缺失即用全局），
///   而非传 JSON null。
///
/// 用途：DagExecutor 构造 NodeContext 时 `deep_merge(initial_config, node_config)`，
/// 让节点定义里写的 NodeDef.config 优先于 run_workflow 传入的全局 config。
pub fn deep_merge(global: &serde_json::Value, node: &serde_json::Value) -> serde_json::Value {
    use serde_json::Value;
    match (global, node) {
        (Value::Object(g), Value::Object(n)) => {
            let mut merged = g.clone();
            for (k, nv) in n {
                // 同 key 递归（支持嵌套对象局部覆盖）；不同类型时递归退化为「节点级直接覆盖」
                let gv = merged.get(k).cloned();
                let merged_v = match gv {
                    Some(gv) => deep_merge(&gv, nv),
                    None => nv.clone(),
                };
                merged.insert(k.clone(), merged_v);
            }
            Value::Object(merged)
        }
        // 节点级为 Null → 保留全局配置（不覆盖）
        (_, Value::Null) => global.clone(),
        // 显式覆盖剩余变体，防止新变体被 _ 吞没
        (Value::Number(_), _)
        | (Value::String(_), _)
        | (Value::Array(_), _)
        | (Value::Bool(_), _)
        | (Value::Null, _)
        | (Value::Object(_), _) => node.clone(),
    }
}

#[cfg(test)]
mod deep_merge_tests {
    use super::deep_merge;
    use serde_json::json;

    #[test]
    fn node_overrides_global_scalar() {
        assert_eq!(deep_merge(&json!({"a": 1}), &json!({"a": 2})), json!({"a": 2}));
    }

    #[test]
    fn node_adds_new_key() {
        assert_eq!(
            deep_merge(&json!({"a": 1}), &json!({"b": 2})),
            json!({"a": 1, "b": 2})
        );
    }

    #[test]
    fn nested_object_recursive_merge() {
        assert_eq!(
            deep_merge(&json!({"o": {"x": 1, "y": 2}}), &json!({"o": {"y": 9}})),
            json!({"o": {"x": 1, "y": 9}})
        );
    }

    #[test]
    fn empty_node_config_is_noop() {
        // 核心保现有调用方行为：节点 config 为空对象 → 结果等同全局（零行为破坏）
        let global = json!({"title": "确认", "options": ["同意"]});
        assert_eq!(deep_merge(&global, &json!({})), global);
    }

    #[test]
    fn null_node_config_keeps_global() {
        // 节点级为 Null → 保留全局（不覆盖），区别于「缺失 key 不调 deep_merge」。
        let global = json!({"a": 1});
        assert_eq!(deep_merge(&global, &json!(null)), global);
    }

    #[test]
    fn array_replaces_not_concat() {
        // 非两端 Object（数组）→ 节点级直接覆盖，不拼接
        assert_eq!(
            deep_merge(&json!({"arr": [1, 2]}), &json!({"arr": [3]})),
            json!({"arr": [3]})
        );
    }
}
