use crate::ir::{Element, NodeId, Value, IRNode, Props};
use indexmap::IndexMap;
use slotmap::SlotMap;
use std::sync::Arc;

/// The kind of control flow node for re-reconciliation
#[derive(Debug, Clone)]
pub enum ControlFlowKind {
    /// ForEach iteration container
    ForEach {
        item_name: String,
        key_path: Option<String>,
    },
    /// Conditional (When/If) container
    Conditional,
}

/// Instance node - a concrete instance of an element in the tree
///
/// Uses im::Vector for children to enable O(1) structural sharing during clones.
/// This is critical for reconciliation performance where nodes are frequently cloned.
#[derive(Debug, Clone)]
pub struct InstanceNode {
    /// Unique node ID
    pub id: NodeId,

    /// Element type (e.g., "Column", "Text", "__ForEach", "__Conditional")
    pub element_type: String,

    /// Resolved props (bindings evaluated to actual values)
    pub props: IndexMap<String, serde_json::Value>,

    /// Raw props (including bindings) for change detection - Arc-wrapped for O(1) clone
    pub raw_props: Props,

    /// Original element template (for List re-rendering) - legacy
    /// Only populated for List elements that need to re-render children
    /// Arc-wrapped for O(1) clone during reconciliation
    pub element_template: Option<Arc<Element>>,

    /// Original IRNode template (for ForEach/Conditional re-rendering)
    /// Used for control flow nodes that need to re-render on state change
    /// Arc-wrapped for O(1) clone during reconciliation
    pub ir_node_template: Option<Arc<IRNode>>,

    /// Control flow metadata for ForEach/Conditional nodes
    pub control_flow: Option<ControlFlowKind>,

    // Event handling removed - now done at renderer level

    /// Optional key for reconciliation
    pub key: Option<String>,

    /// Parent node ID
    pub parent: Option<NodeId>,

    /// Child node IDs (ordered) - uses im::Vector for O(1) clone
    pub children: im::Vector<NodeId>,
}

impl InstanceNode {
    pub fn new(id: NodeId, element: &Element, state: &serde_json::Value) -> Self {
        let props = resolve_props(&element.props, state);

        Self {
            id,
            element_type: element.element_type.clone(),
            props,
            raw_props: element.props.clone(),
            element_template: None,
            ir_node_template: None,
            control_flow: None,
            key: element.key.clone(),
            parent: None,
            children: im::Vector::new(),
        }
    }

    /// Create a control flow container node (ForEach or Conditional)
    pub fn new_control_flow(
        id: NodeId,
        element_type: &str,
        props: IndexMap<String, serde_json::Value>,
        raw_props: Props,
        control_flow: ControlFlowKind,
        ir_node_template: IRNode,
    ) -> Self {
        Self {
            id,
            element_type: element_type.to_string(),
            props,
            raw_props,
            element_template: None,
            ir_node_template: Some(Arc::new(ir_node_template)),
            control_flow: Some(control_flow),
            key: None,
            parent: None,
            children: im::Vector::new(),
        }
    }

    /// Update props by re-evaluating bindings against new state
    pub fn update_props(&mut self, state: &serde_json::Value) {
        self.props = resolve_props(&self.raw_props, state);
    }

    /// Check if this is a ForEach control flow node
    pub fn is_foreach(&self) -> bool {
        matches!(self.control_flow, Some(ControlFlowKind::ForEach { .. }))
    }

    /// Check if this is a Conditional control flow node
    pub fn is_conditional(&self) -> bool {
        matches!(self.control_flow, Some(ControlFlowKind::Conditional))
    }
}

/// The instance tree - maintains the current UI tree state
pub struct InstanceTree {
    /// All nodes in the tree
    nodes: SlotMap<NodeId, InstanceNode>,

    /// Root node ID
    root: Option<NodeId>,
}

impl InstanceTree {
    pub fn new() -> Self {
        Self {
            nodes: SlotMap::with_key(),
            root: None,
        }
    }

    /// Clear all nodes and reset the tree
    pub fn clear(&mut self) {
        self.nodes.clear();
        self.root = None;
    }

    /// Create a new node and return its ID
    pub fn create_node(&mut self, element: &Element, state: &serde_json::Value) -> NodeId {
        let id = self.nodes.insert_with_key(|id| InstanceNode::new(id, element, state));
        id
    }

    /// Create a control flow node (ForEach or Conditional) and return its ID
    pub fn create_control_flow_node(
        &mut self,
        element_type: &str,
        props: IndexMap<String, serde_json::Value>,
        raw_props: Props,
        control_flow: ControlFlowKind,
        ir_node_template: IRNode,
    ) -> NodeId {
        self.nodes.insert_with_key(|id| {
            InstanceNode::new_control_flow(id, element_type, props, raw_props, control_flow, ir_node_template)
        })
    }

    /// Get a node by ID
    pub fn get(&self, id: NodeId) -> Option<&InstanceNode> {
        self.nodes.get(id)
    }

    /// Get a mutable node by ID
    pub fn get_mut(&mut self, id: NodeId) -> Option<&mut InstanceNode> {
        self.nodes.get_mut(id)
    }

    /// Remove a node and all its descendants
    pub fn remove(&mut self, id: NodeId) -> Option<InstanceNode> {
        if let Some(node) = self.nodes.get(id) {
            let children = node.children.clone();
            // Remove all children recursively
            for child_id in children {
                self.remove(child_id);
            }
        }
        self.nodes.remove(id)
    }

    /// Set the root node
    pub fn set_root(&mut self, id: NodeId) {
        self.root = Some(id);
    }

    /// Get the root node ID
    pub fn root(&self) -> Option<NodeId> {
        self.root
    }

    /// Add a child to a parent node
    pub fn add_child(&mut self, parent_id: NodeId, child_id: NodeId, before: Option<NodeId>) {
        if let Some(parent) = self.nodes.get_mut(parent_id) {
            if let Some(before_id) = before {
                if let Some(pos) = parent.children.iter().position(|&id| id == before_id) {
                    parent.children.insert(pos, child_id);
                } else {
                    parent.children.push_back(child_id);
                }
            } else {
                parent.children.push_back(child_id);
            }
        }

        if let Some(child) = self.nodes.get_mut(child_id) {
            child.parent = Some(parent_id);
        }
    }

    /// Remove a child from its parent
    pub fn remove_child(&mut self, parent_id: NodeId, child_id: NodeId) {
        if let Some(parent) = self.nodes.get_mut(parent_id) {
            parent.children = parent.children.iter().filter(|&&id| id != child_id).copied().collect();
        }

        if let Some(child) = self.nodes.get_mut(child_id) {
            child.parent = None;
        }
    }

    /// Update all nodes that depend on changed state
    pub fn update_nodes(&mut self, node_ids: &indexmap::IndexSet<NodeId>, state: &serde_json::Value) {
        for &node_id in node_ids {
            if let Some(node) = self.nodes.get_mut(node_id) {
                node.update_props(state);
            }
        }
    }

    /// Iterate over all nodes
    pub fn iter(&self) -> impl Iterator<Item = (NodeId, &InstanceNode)> {
        self.nodes.iter()
    }
}

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

/// Resolve props by evaluating bindings against current state
fn resolve_props(props: &IndexMap<String, Value>, state: &serde_json::Value) -> IndexMap<String, serde_json::Value> {
    resolve_props_with_item(props, state, None)
}

/// Resolve props with optional item context (for list iteration)
fn resolve_props_with_item(
    props: &IndexMap<String, Value>,
    state: &serde_json::Value,
    item: Option<&serde_json::Value>,
) -> IndexMap<String, serde_json::Value> {
    let mut resolved = IndexMap::new();

    for (key, value) in props {
        let resolved_value = match value {
            Value::Static(v) => v.clone(),
            Value::Binding(binding) => {
                if binding.is_item() {
                    // Evaluate item binding
                    if let Some(item_value) = item {
                        evaluate_item_binding(binding, item_value).unwrap_or(serde_json::Value::Null)
                    } else {
                        serde_json::Value::Null
                    }
                } else {
                    // Evaluate state binding
                    evaluate_binding(binding, state).unwrap_or(serde_json::Value::Null)
                }
            }
            Value::TemplateString { template, .. } => {
                // Use expression evaluation for template strings - handles both
                // simple bindings and complex expressions like ternaries
                match crate::reactive::evaluate_template_string(template, state, item) {
                    Ok(result) => serde_json::Value::String(result),
                    Err(_) => serde_json::Value::String(template.clone()),
                }
            }
            Value::Action(action) => {
                // Actions are serialized with @ prefix for renderer to detect
                serde_json::Value::String(format!("@{}", action))
            }
        };
        resolved.insert(key.clone(), resolved_value);
    }

    resolved
}

/// Evaluate an item binding against the item object
fn evaluate_item_binding(binding: &crate::reactive::Binding, item: &serde_json::Value) -> Option<serde_json::Value> {
    if binding.path.is_empty() {
        // Bare @item - return the whole item
        return Some(item.clone());
    }

    let mut current = item;
    for segment in &binding.path {
        current = current.get(segment)?;
    }
    Some(current.clone())
}

/// Evaluate a binding against the state object using its parsed path
fn evaluate_binding(binding: &crate::reactive::Binding, state: &serde_json::Value) -> Option<serde_json::Value> {
    let mut current = state;

    for segment in &binding.path {
        current = current.get(segment)?;
    }

    Some(current.clone())
}

#[cfg(test)]
mod tests {
    use super::*;
    use serde_json::json;

    #[test]
    fn test_evaluate_binding() {
        use crate::reactive::Binding;

        let state = json!({
            "user": {
                "name": "Alice",
                "age": 30
            }
        });

        let name_binding = Binding::state(vec!["user".to_string(), "name".to_string()]);
        let age_binding = Binding::state(vec!["user".to_string(), "age".to_string()]);
        let email_binding = Binding::state(vec!["user".to_string(), "email".to_string()]);

        assert_eq!(
            evaluate_binding(&name_binding, &state),
            Some(json!("Alice"))
        );
        assert_eq!(
            evaluate_binding(&age_binding, &state),
            Some(json!(30))
        );
        assert_eq!(evaluate_binding(&email_binding, &state), None);
    }
}
