use serde::{Deserialize, Serialize};
use serde_json::Value;
use std::collections::BTreeMap;

#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
#[serde(rename_all = "camelCase")]
pub struct MindmapNodeRef {
    pub kind: String,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub asset_id: Option<String>,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub file_url: Option<String>,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub page: Option<u32>,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub slide: Option<u32>,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub title: Option<String>,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub snippet: Option<String>,
}

#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
#[serde(rename_all = "camelCase")]
pub struct MindmapNodeData {
    #[serde(skip_serializing_if = "Option::is_none")]
    pub uid: Option<String>,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub text: Option<String>,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub hyperlink: Option<String>,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub note: Option<String>,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub refs: Option<Vec<MindmapNodeRef>>,
    #[serde(flatten, default)]
    pub extra: BTreeMap<String, Value>,
}

#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
pub struct MindmapTreeNode {
    pub data: MindmapNodeData,
    #[serde(default)]
    pub children: Vec<MindmapTreeNode>,
    #[serde(flatten, default)]
    pub extra: BTreeMap<String, Value>,
}

#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
#[serde(rename_all = "camelCase")]
pub struct MindmapNodeInput {
    #[serde(skip_serializing_if = "Option::is_none")]
    pub uid: Option<String>,
    pub text: String,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub hyperlink: Option<String>,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub note: Option<String>,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub refs: Option<Vec<MindmapNodeRef>>,
}

#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
#[serde(tag = "op", rename_all = "camelCase")]
pub enum MindmapOp {
    #[serde(alias = "add_child")]
    AddChild {
        #[serde(rename = "parentUid")]
        #[serde(alias = "parent_uid")]
        parent_uid: String,
        node: MindmapNodeInput,
    },
    #[serde(alias = "add_sibling_after")]
    AddSiblingAfter {
        #[serde(rename = "targetUid")]
        #[serde(alias = "target_uid")]
        target_uid: String,
        node: MindmapNodeInput,
    },
    #[serde(alias = "update_node", alias = "updateNode")]
    UpdateText {
        uid: String,
        #[serde(alias = "value")]
        text: String,
    },
    #[serde(alias = "set_link", alias = "set_hyperlink")]
    SetHyperlink {
        #[serde(alias = "id")]
        uid: String,
        #[serde(alias = "url")]
        hyperlink: Option<String>,
    },
    #[serde(alias = "set_refs")]
    SetRefs {
        #[serde(alias = "id")]
        uid: String,
        refs: Vec<MindmapNodeRef>,
    },
    #[serde(alias = "append_note")]
    AppendNote {
        #[serde(alias = "id")]
        uid: String,
        #[serde(alias = "note")]
        markdown: String,
    },
    #[serde(alias = "delete_node")]
    DeleteNode {
        #[serde(alias = "id")]
        uid: String,
    },
}
