//! block menu 使用的顶层块 JSON helper。

use serde_json::{json, Map, Value};

fn node_with_attrs(
    type_name: &str,
    attrs: Option<Map<String, Value>>,
    content: Vec<Value>,
) -> Value {
    let mut node = Map::new();
    node.insert("type".to_string(), Value::String(type_name.to_string()));
    if let Some(attrs) = attrs.filter(|attrs| !attrs.is_empty()) {
        node.insert("attrs".to_string(), Value::Object(attrs));
    }
    if !content.is_empty() {
        node.insert("content".to_string(), Value::Array(content));
    }
    Value::Object(node)
}

pub(crate) fn paragraph_node(content: Vec<Value>) -> Value {
    node_with_attrs("paragraph", None, content)
}

pub(crate) fn collect_plain_text(node: &Value) -> String {
    match node.get("type").and_then(Value::as_str) {
        Some("text") => node
            .get("text")
            .and_then(Value::as_str)
            .unwrap_or_default()
            .to_string(),
        Some("hardBreak") => "\n".to_string(),
        _ => node
            .get("content")
            .and_then(Value::as_array)
            .map(|children| {
                children
                    .iter()
                    .map(collect_plain_text)
                    .collect::<Vec<_>>()
                    .join("")
            })
            .unwrap_or_default(),
    }
}

pub(crate) fn mindmap_paragraph_node(next_mindmap_id: impl FnOnce() -> String) -> Value {
    let mut attrs = Map::new();
    attrs.insert("mnoteBlockType".to_string(), json!("mindmap"));
    attrs.insert("mindmapId".to_string(), json!(next_mindmap_id()));
    attrs.insert("rootNodeId".to_string(), json!("root"));
    attrs.insert("projectionVersion".to_string(), json!(1));
    node_with_attrs("paragraph", Some(attrs), Vec::new())
}
