//! Inspector node types for the process tree.
//!
//! These types represent nodes in the inspector's hierarchical process tree,
//! providing a canonical definition that can be shared between the server-side
//! inspector and WASM-based UI.

use serde::{Deserialize, Serialize};
use std::collections::HashMap;
use std::fmt;

/// Hierarchical identifier for a node in the inspector tree.
///
/// Uses `/`-separated segments (e.g., `"root/connector-1/process-a"`).
#[derive(Clone, Debug, Hash, Eq, PartialEq, Serialize, Deserialize)]
pub struct NodeId(pub String);

impl NodeId {
    pub fn new(id: impl Into<String>) -> Self {
        Self(id.into())
    }

    /// Create a child node ID by appending a segment.
    pub fn child(&self, segment: &str) -> Self {
        Self(format!("{}/{}", self.0, segment))
    }

    /// Get the parent node ID (everything before the last `/`).
    pub fn parent(&self) -> Option<Self> {
        self.0.rfind('/').map(|idx| Self(self.0[..idx].to_string()))
    }

    /// Get the last segment of the path (the node's own name).
    pub fn name(&self) -> &str {
        self.0.rsplit('/').next().unwrap_or(&self.0)
    }

    pub fn as_str(&self) -> &str {
        &self.0
    }
}

impl fmt::Display for NodeId {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        write!(f, "{}", self.0)
    }
}

impl From<&str> for NodeId {
    fn from(s: &str) -> Self {
        Self(s.to_string())
    }
}

impl From<String> for NodeId {
    fn from(s: String) -> Self {
        Self(s)
    }
}

/// The kind of node in the inspector tree.
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
pub enum NodeKind {
    Root,
    Connector,
    Process,
    Service,
    AsyncTask,
    System,
    Custom(String),
}

impl fmt::Display for NodeKind {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        match self {
            NodeKind::Root => write!(f, "Root"),
            NodeKind::Connector => write!(f, "Connector"),
            NodeKind::Process => write!(f, "Process"),
            NodeKind::Service => write!(f, "Service"),
            NodeKind::AsyncTask => write!(f, "AsyncTask"),
            NodeKind::System => write!(f, "System"),
            NodeKind::Custom(name) => write!(f, "Custom({})", name),
        }
    }
}

/// The runtime state of an inspector node.
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
pub enum NodeState {
    Initializing,
    Running,
    Idle,
    Busy(String),
    Degraded(String),
    Error(String),
    Stopped,
}

impl fmt::Display for NodeState {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        match self {
            NodeState::Initializing => write!(f, "Initializing"),
            NodeState::Running => write!(f, "Running"),
            NodeState::Idle => write!(f, "Idle"),
            NodeState::Busy(desc) => write!(f, "Busy({})", desc),
            NodeState::Degraded(reason) => write!(f, "Degraded({})", reason),
            NodeState::Error(msg) => write!(f, "Error({})", msg),
            NodeState::Stopped => write!(f, "Stopped"),
        }
    }
}

/// Metadata associated with an inspector node.
#[derive(Clone, Debug, Serialize, Deserialize)]
pub struct NodeMetadata {
    pub kind: NodeKind,
    pub label: String,
    pub state: NodeState,
    pub created_at: chrono::DateTime<chrono::Utc>,
    pub last_updated: chrono::DateTime<chrono::Utc>,
    pub properties: HashMap<String, serde_json::Value>,
}

impl NodeMetadata {
    pub fn new(kind: NodeKind, label: impl Into<String>) -> Self {
        let now = chrono::Utc::now();
        Self {
            kind,
            label: label.into(),
            state: NodeState::Initializing,
            created_at: now,
            last_updated: now,
            properties: HashMap::new(),
        }
    }

    pub fn with_state(mut self, state: NodeState) -> Self {
        self.state = state;
        self
    }

    pub fn with_property(mut self, key: impl Into<String>, value: serde_json::Value) -> Self {
        self.properties.insert(key.into(), value);
        self
    }
}
