use super::context_item::ContextItem;
use crate::events::{Consumer, Event};
use crate::tools::{get_global_registry, Tool};
use serde_json::Value;
use std::collections::HashMap;
use std::sync::{Arc, Mutex};

/// A general-purpose context that can store both global and scoped variables.
///
/// This context supports:
/// - Global variables that persist throughout the entire lifetime
/// - Scoped variables that are organized in a stack-based hierarchy
/// - Automatic scope management based on block events
///
/// The Context implements the Consumer trait to automatically manage scopes
/// based on BlockStarted/BlockFinished events. Each block level gets its own scope.
#[derive(Clone, Debug)]
pub struct Context {
    /// Global items that persist across all scopes
    global_items: Arc<Mutex<HashMap<String, ContextItem>>>,
    /// Scoped variables: outer Vec represents stack levels, inner HashMap contains variables at that level
    scoped_items: Arc<Mutex<Vec<HashMap<String, ContextItem>>>>,
    /// Track current stack depth for scoped variables
    current_depth: Arc<Mutex<usize>>,
    /// Track the block nesting level for automatic scope management
    block_level: Arc<Mutex<usize>>,
    /// Tools that can be executed in this context
    tools: Arc<Mutex<Vec<Tool>>>,
}

impl Context {
    /// Create a new empty context
    pub fn new() -> Self {
        Self {
            global_items: Arc::new(Mutex::new(HashMap::new())),
            scoped_items: Arc::new(Mutex::new(vec![HashMap::new()])), // Start with one scope
            current_depth: Arc::new(Mutex::new(0)),
            block_level: Arc::new(Mutex::new(0)),
            tools: Arc::new(Mutex::new(Vec::new())),
        }
    }

    /// Create a new context with the given tools
    pub fn with_tools(tools: Vec<Tool>) -> Self {
        Self {
            global_items: Arc::new(Mutex::new(HashMap::new())),
            scoped_items: Arc::new(Mutex::new(vec![HashMap::new()])), // Start with one scope
            current_depth: Arc::new(Mutex::new(0)),
            block_level: Arc::new(Mutex::new(0)),
            tools: Arc::new(Mutex::new(tools)),
        }
    }

    /// Get a reference to the tools
    pub fn tools(&self) -> Vec<Tool> {
        self.tools.lock().unwrap().clone()
    }

    /// Enable a tool by name from the global tool registry
    pub fn enable_tool(&self, name: &str) -> Result<(), String> {
        let global_registry = get_global_registry();
        let registry_guard = global_registry.lock().unwrap();

        if let Some(tool) = registry_guard.find_tool_by_name(name) {
            let mut tools_guard = self.tools.lock().unwrap();
            // Check if tool is already enabled
            if !tools_guard.iter().any(|t| t.name == name) {
                tools_guard.push(tool.clone());
                Ok(())
            } else {
                Err(format!("Tool '{name}' is already enabled"))
            }
        } else {
            Err(format!("Tool '{name}' not found in registry"))
        }
    }

    /// Add a tool directly to the context (used by import tool)
    pub fn add_tool(&self, tool: Tool) -> Result<(), String> {
        let mut tools_guard = self.tools.lock().unwrap();
        // Check if tool is already added
        if !tools_guard.iter().any(|t| t.name == tool.name) {
            tools_guard.push(tool);
            Ok(())
        } else {
            Err(format!("Tool '{}' is already added", tool.name))
        }
    }

    /// Put a global value that persists across all scopes
    pub fn put(&self, key: String, value: Value) {
        let mut items = self.global_items.lock().unwrap();
        items.insert(key.clone(), ContextItem::new(key, value));
    }

    /// Put a global value from any serializable type
    pub fn put_serializable<T: serde::Serialize>(
        &self,
        key: String,
        value: T,
    ) -> Result<(), serde_json::Error> {
        let item = ContextItem::from_serializable(key.clone(), value)?;
        let mut items = self.global_items.lock().unwrap();
        items.insert(key, item);
        Ok(())
    }

    /// Get a value, checking scoped variables first, then global variables
    pub fn get(&self, key: &str) -> Option<Value> {
        // First check scoped variables (from current level up to root)
        let scoped = self.scoped_items.lock().unwrap();
        let depth = *self.current_depth.lock().unwrap();

        // Search from current depth up to root (0)
        for level in (0..=depth.min(scoped.len().saturating_sub(1))).rev() {
            if let Some(scope) = scoped.get(level) {
                if let Some(item) = scope.get(key) {
                    return Some(item.value.clone());
                }
            }
        }

        // Fall back to global items
        let items = self.global_items.lock().unwrap();
        items.get(key).map(|item| item.value.clone())
    }

    /// Get a value as a specific type
    pub fn get_as<T: for<'de> serde::Deserialize<'de>>(&self, key: &str) -> Option<T> {
        self.get(key)
            .and_then(|value| serde_json::from_value(value).ok())
    }

    /// Put a scoped variable at the current stack level
    pub fn put_scoped(&self, key: String, value: Value) {
        let mut scoped = self.scoped_items.lock().unwrap();
        let depth = *self.current_depth.lock().unwrap();

        // Ensure we have enough levels
        while scoped.len() <= depth {
            scoped.push(HashMap::new());
        }

        if let Some(scope) = scoped.get_mut(depth) {
            scope.insert(key.clone(), ContextItem::new(key, value));
        }
    }

    /// Put a scoped variable from any serializable type
    pub fn put_scoped_serializable<T: serde::Serialize>(
        &self,
        key: String,
        value: T,
    ) -> Result<(), serde_json::Error> {
        let item = ContextItem::from_serializable(key.clone(), value)?;
        let mut scoped = self.scoped_items.lock().unwrap();
        let depth = *self.current_depth.lock().unwrap();

        // Ensure we have enough levels
        while scoped.len() <= depth {
            scoped.push(HashMap::new());
        }

        if let Some(scope) = scoped.get_mut(depth) {
            scope.insert(key, item);
        }
        Ok(())
    }

    /// Get a scoped variable (searches from current level up to root)
    pub fn get_scoped(&self, key: &str) -> Option<Value> {
        let scoped = self.scoped_items.lock().unwrap();
        let depth = *self.current_depth.lock().unwrap();

        // Search from current depth up to root (0)
        for level in (0..=depth.min(scoped.len().saturating_sub(1))).rev() {
            if let Some(scope) = scoped.get(level) {
                if let Some(item) = scope.get(key) {
                    return Some(item.value.clone());
                }
            }
        }

        None
    }

    /// Get a scoped variable as a specific type
    pub fn get_scoped_as<T: for<'de> serde::Deserialize<'de>>(&self, key: &str) -> Option<T> {
        self.get_scoped(key)
            .and_then(|value| serde_json::from_value(value).ok())
    }

    /// Push a new scope level
    pub fn push_scope(&self) {
        let mut scoped = self.scoped_items.lock().unwrap();
        let mut depth = self.current_depth.lock().unwrap();

        *depth += 1;

        // Ensure we have a HashMap at the new depth
        while scoped.len() <= *depth {
            scoped.push(HashMap::new());
        }
    }

    /// Pop a scope level and discard its variables
    pub fn pop_scope(&self) {
        let mut scoped = self.scoped_items.lock().unwrap();
        let mut depth = self.current_depth.lock().unwrap();

        if *depth > 0 {
            // Clear the current scope's variables
            if let Some(scope) = scoped.get_mut(*depth) {
                scope.clear();
            }
            *depth -= 1;
        }
    }

    /// Get the current scope depth
    pub fn current_depth(&self) -> usize {
        *self.current_depth.lock().unwrap()
    }

    /// Get all global items
    pub fn global_items(&self) -> HashMap<String, Value> {
        let items = self.global_items.lock().unwrap();
        items
            .iter()
            .map(|(k, v)| (k.clone(), v.value.clone()))
            .collect()
    }

    /// Get all visible scoped items (merged from all levels up to current)
    pub fn visible_scoped_items(&self) -> HashMap<String, Value> {
        let scoped = self.scoped_items.lock().unwrap();
        let depth = *self.current_depth.lock().unwrap();
        let mut result = HashMap::new();

        // Add variables from all levels up to current depth (root to current)
        for level in 0..=depth.min(scoped.len().saturating_sub(1)) {
            if let Some(scope) = scoped.get(level) {
                for (k, v) in scope.iter() {
                    result.insert(k.clone(), v.value.clone());
                }
            }
        }

        result
    }

    /// Clear all global items
    pub fn clear_global(&self) {
        let mut items = self.global_items.lock().unwrap();
        items.clear();
    }

    /// Clear all scoped items at the current level
    pub fn clear_current_scope(&self) {
        let mut scoped = self.scoped_items.lock().unwrap();
        let depth = *self.current_depth.lock().unwrap();

        if let Some(scope) = scoped.get_mut(depth) {
            scope.clear();
        }
    }

    /// Handle an event for automatic scope management
    /// This is a non-mut version that works with the internal Arc<Mutex<>> fields
    pub fn handle_event(&self, event: &Event) {
        match event {
            Event::BlockStarted { meta_line } => {
                let mut block_level = self.block_level.lock().unwrap();
                let new_level = meta_line.level;
                let old_block_level = *block_level;

                // Adjust scope depth based on block level changes
                let mut current_depth = self.current_depth.lock().unwrap();

                // If we're going deeper into nesting, push new scopes
                if new_level > old_block_level {
                    while *current_depth < new_level {
                        *current_depth += 1;
                        let mut scoped = self.scoped_items.lock().unwrap();
                        while scoped.len() <= *current_depth {
                            scoped.push(HashMap::new());
                        }
                    }
                }
                // If we're going up in nesting, pop scopes
                else if new_level < old_block_level {
                    let mut scoped = self.scoped_items.lock().unwrap();

                    // Clear scopes that are deeper than the new level
                    while *current_depth > new_level {
                        if let Some(scope) = scoped.get_mut(*current_depth) {
                            scope.clear();
                        }
                        *current_depth -= 1;
                    }

                    // Also clear the current level since we're moving to a new block
                    if let Some(scope) = scoped.get_mut(*current_depth) {
                        scope.clear();
                    }
                }
                // If we're at the same level (sibling blocks), clear the current scope
                else if new_level == old_block_level && old_block_level > 0 {
                    let mut scoped = self.scoped_items.lock().unwrap();
                    // Clear the current level scope to give the new sibling a fresh scope
                    if let Some(scope) = scoped.get_mut(*current_depth) {
                        scope.clear();
                    }
                }

                *block_level = new_level;

                // Special case: if this is the first block (old_block_level was 0),
                // we need to set the depth correctly
                if old_block_level == 0 && new_level > 0 {
                    *current_depth = new_level;
                    let mut scoped = self.scoped_items.lock().unwrap();
                    while scoped.len() <= *current_depth {
                        scoped.push(HashMap::new());
                    }
                }
            }
            Event::BlockFinished => {
                // BlockFinished doesn't directly tell us the new level,
                // but we can track it based on our understanding of the structure.
                // In practice, this is handled by the next BlockStarted event
                // adjusting the level appropriately.
            }
            Event::TextFinished { .. } => {
                // Text events don't affect scope
            }
            Event::ContextLine { .. } => {
                // Context lines don't affect scope
            }
            Event::VoidElement { .. } => {
                // Void elements are self-closing and don't affect scope
                // They don't push/pop the block stack
            }
        }
    }
}

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

impl Consumer for Context {
    fn handle(&mut self, event: Event) {
        // Delegate to the non-mut version since we use Arc<Mutex<>> internally
        self.handle_event(&event);
    }
}

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

    #[test]
    fn test_context_creation() {
        let context = Context::new();
        assert_eq!(context.current_depth(), 0);
    }

    #[test]
    fn test_global_put_and_get() {
        let context = Context::new();
        context.put("key1".to_string(), json!("value1"));

        let value = context.get("key1");
        assert_eq!(value, Some(json!("value1")));

        let nonexistent = context.get("nonexistent");
        assert_eq!(nonexistent, None);
    }

    #[test]
    fn test_global_serializable() {
        let context = Context::new();
        context.put_serializable("number".to_string(), 42).unwrap();

        let value: Option<i32> = context.get_as("number");
        assert_eq!(value, Some(42));
    }

    #[test]
    fn test_scoped_variables() {
        let context = Context::new();

        // Put a scoped variable at level 0
        context.put_scoped("scoped_key".to_string(), json!("scoped_value"));

        // Should be retrievable via get_scoped
        let value = context.get_scoped("scoped_key");
        assert_eq!(value, Some(json!("scoped_value")));

        // Should also be retrievable via regular get (which checks scoped first)
        let value = context.get("scoped_key");
        assert_eq!(value, Some(json!("scoped_value")));
    }

    #[test]
    fn test_scope_push_and_pop() {
        let context = Context::new();

        // Add variable at root scope
        context.put_scoped("root_var".to_string(), json!("root"));

        // Push new scope
        context.push_scope();
        assert_eq!(context.current_depth(), 1);

        // Root variable should still be accessible
        assert_eq!(context.get_scoped("root_var"), Some(json!("root")));

        // Add variable in new scope
        context.put_scoped("child_var".to_string(), json!("child"));
        assert_eq!(context.get_scoped("child_var"), Some(json!("child")));

        // Pop scope
        context.pop_scope();
        assert_eq!(context.current_depth(), 0);

        // Child variable should be gone
        assert_eq!(context.get_scoped("child_var"), None);

        // Root variable should still be there
        assert_eq!(context.get_scoped("root_var"), Some(json!("root")));
    }

    #[test]
    fn test_scope_shadowing() {
        let context = Context::new();

        // Set variable at root
        context.put_scoped("var".to_string(), json!("root_value"));

        // Push scope and shadow the variable
        context.push_scope();
        context.put_scoped("var".to_string(), json!("child_value"));

        // Should get the child value
        assert_eq!(context.get("var"), Some(json!("child_value")));

        // Pop scope
        context.pop_scope();

        // Should get the root value again
        assert_eq!(context.get("var"), Some(json!("root_value")));
    }

    #[test]
    fn test_global_vs_scoped_priority() {
        let context = Context::new();

        // Set global variable
        context.put("key".to_string(), json!("global"));

        // Set scoped variable with same key
        context.put_scoped("key".to_string(), json!("scoped"));

        // Scoped should take priority
        assert_eq!(context.get("key"), Some(json!("scoped")));

        // Push new scope without shadowing
        context.push_scope();

        // Should still get scoped value from parent scope
        assert_eq!(context.get("key"), Some(json!("scoped")));

        // Shadow in new scope
        context.put_scoped("key".to_string(), json!("new_scoped"));
        assert_eq!(context.get("key"), Some(json!("new_scoped")));

        // Pop all scopes
        context.pop_scope();
        context.pop_scope(); // This won't go below 0

        // Clear scoped at root
        context.clear_current_scope();

        // Now should get global value
        assert_eq!(context.get("key"), Some(json!("global")));
    }

    #[test]
    fn test_visible_scoped_items() {
        let context = Context::new();

        context.put_scoped("level0".to_string(), json!("val0"));
        context.push_scope();
        context.put_scoped("level1".to_string(), json!("val1"));

        let visible = context.visible_scoped_items();
        assert_eq!(visible.get("level0"), Some(&json!("val0")));
        assert_eq!(visible.get("level1"), Some(&json!("val1")));
    }

    #[test]
    fn test_global_items() {
        let context = Context::new();

        context.put("global1".to_string(), json!("g1"));
        context.put("global2".to_string(), json!("g2"));

        let globals = context.global_items();
        assert_eq!(globals.len(), 2);
        assert_eq!(globals.get("global1"), Some(&json!("g1")));
        assert_eq!(globals.get("global2"), Some(&json!("g2")));
    }

    #[test]
    fn test_clear_operations() {
        let context = Context::new();

        // Add global and scoped items
        context.put("global".to_string(), json!("g"));
        context.put_scoped("scoped".to_string(), json!("s"));

        // Clear global
        context.clear_global();
        assert_eq!(context.global_items().len(), 0);
        assert_eq!(context.get_scoped("scoped"), Some(json!("s")));

        // Clear current scope
        context.clear_current_scope();
        assert_eq!(context.get_scoped("scoped"), None);
    }

    #[test]
    fn test_complex_types() {
        let context = Context::new();

        // Store array
        context.put("array".to_string(), json!([1, 2, 3]));
        let arr: Option<Vec<i32>> = context.get_as("array");
        assert_eq!(arr, Some(vec![1, 2, 3]));

        // Store object
        context.put("object".to_string(), json!({"name": "test", "value": 42}));
        let obj = context.get("object");
        assert!(obj.is_some());
        if let Some(Value::Object(map)) = obj {
            assert_eq!(map.get("name"), Some(&json!("test")));
            assert_eq!(map.get("value"), Some(&json!(42)));
        }
    }

    #[test]
    fn test_context_cloning() {
        let context1 = Context::new();
        context1.put("shared".to_string(), json!("value"));

        let context2 = context1.clone();

        // Both should see the same value
        assert_eq!(context2.get("shared"), Some(json!("value")));

        // Adding to one should affect the other
        context2.put("new".to_string(), json!("new_value"));
        assert_eq!(context1.get("new"), Some(json!("new_value")));
    }

    #[test]
    fn test_enable_tool() {
        let context = Context::new();

        // Initially no tools
        assert_eq!(context.tools().len(), 0);

        // Try to enable a non-existent tool
        let result = context.enable_tool("nonexistent");
        assert!(result.is_err());
        assert_eq!(
            result.unwrap_err(),
            "Tool 'nonexistent' not found in registry"
        );

        // Note: In a real test, we'd need to register some tools in the global registry first
        // This test mainly verifies the function signature and basic error handling
    }

    #[test]
    fn test_import_tool_available() {
        use crate::tools::get_global_registry;

        // The import tool should be automatically registered in the global registry
        let global_registry = get_global_registry();
        let registry_guard = global_registry.lock().unwrap();

        // Check that the import tool is available
        let import_tool = registry_guard.find_tool_by_name("import");
        assert!(
            import_tool.is_some(),
            "Import tool should be available in global registry"
        );

        let tool = import_tool.unwrap();
        assert_eq!(tool.name, "import");
    }

    #[test]
    fn test_add_tool() {
        use crate::events::Event;
        use crate::tools::{Tool, ToolCallback};

        struct DummyTool;
        impl ToolCallback for DummyTool {
            fn handle(&self, _event: &Event, _context: Context) {}
            fn as_any(&self) -> &dyn std::any::Any {
                self
            }
        }

        let context = Context::new();
        let dummy_tool = Tool::new(
            "dummy".to_string(),
            vec!["dummy".to_string()],
            Box::new(DummyTool),
        )
        .unwrap();

        // Initially no tools
        assert_eq!(context.tools().len(), 0);

        // Add a tool
        let result = context.add_tool(dummy_tool);
        assert!(result.is_ok());
        assert_eq!(context.tools().len(), 1);
        assert_eq!(context.tools()[0].name, "dummy");

        // Try to add the same tool again
        let dummy_tool2 = Tool::new(
            "dummy".to_string(),
            vec!["dummy".to_string()],
            Box::new(DummyTool),
        )
        .unwrap();
        let result2 = context.add_tool(dummy_tool2);
        assert!(result2.is_err());
        assert_eq!(result2.unwrap_err(), "Tool 'dummy' is already added");

        // Should still have only one tool
        assert_eq!(context.tools().len(), 1);
    }

    #[test]
    fn test_event_based_scope_management() {
        use crate::events::Event;
        use crate::parsers::wasot::{Id, MetaLine, ParsedArguments, QuotedString};

        let mut context = Context::new();

        // Start with first block at level 1
        let event = Event::BlockStarted {
            meta_line: MetaLine {
                level: 1,
                type_name: "block1".to_string(),
                id: Id::new("".to_string()),
                arguments: ParsedArguments {
                    args: vec![],
                    kwargs: vec![],
                },
                inline_text: QuotedString::new("".to_string(), false),
                line_index: Some(0),
                is_void: false,
            },
        };
        context.handle(event);

        // Add a variable in block1
        context.put_scoped("var1".to_string(), json!("from_block1"));
        assert_eq!(context.get("var1"), Some(json!("from_block1")));

        // Move to sibling block at same level
        let event = Event::BlockStarted {
            meta_line: MetaLine {
                level: 1,
                type_name: "block2".to_string(),
                id: Id::new("".to_string()),
                arguments: ParsedArguments {
                    args: vec![],
                    kwargs: vec![],
                },
                inline_text: QuotedString::new("".to_string(), false),
                line_index: Some(1),
                is_void: false,
            },
        };
        context.handle(event);

        // Variable from block1 should NOT be visible in block2
        assert_eq!(context.get("var1"), None);

        // Add a variable in block2
        context.put_scoped("var2".to_string(), json!("from_block2"));
        assert_eq!(context.get("var2"), Some(json!("from_block2")));

        // Go deeper to level 2 (child of block2)
        let event = Event::BlockStarted {
            meta_line: MetaLine {
                level: 2,
                type_name: "child".to_string(),
                id: Id::new("".to_string()),
                arguments: ParsedArguments {
                    args: vec![],
                    kwargs: vec![],
                },
                inline_text: QuotedString::new("".to_string(), false),
                line_index: Some(2),
                is_void: false,
            },
        };
        context.handle(event);

        // Should see parent's variable
        assert_eq!(context.get("var2"), Some(json!("from_block2")));
        // But not sibling's variable
        assert_eq!(context.get("var1"), None);

        // Add a variable at child level
        context.put_scoped("child_var".to_string(), json!("from_child"));

        // Go back to level 1 with a new sibling
        let event = Event::BlockStarted {
            meta_line: MetaLine {
                level: 1,
                type_name: "block3".to_string(),
                id: Id::new("".to_string()),
                arguments: ParsedArguments {
                    args: vec![],
                    kwargs: vec![],
                },
                inline_text: QuotedString::new("".to_string(), false),
                line_index: Some(3),
                is_void: false,
            },
        };
        context.handle(event);

        // Should not see any previous variables
        assert_eq!(context.get("var1"), None);
        assert_eq!(context.get("var2"), None);
        assert_eq!(context.get("child_var"), None);
    }

    #[test]
    fn test_sibling_scope_isolation() {
        use crate::events::Event;
        use crate::parsers::wasot::{Id, MetaLine, ParsedArguments, QuotedString};

        let mut context = Context::new();

        // Test that sibling blocks don't share scopes
        for i in 1..=3 {
            let event = Event::BlockStarted {
                meta_line: MetaLine {
                    level: 1,
                    type_name: format!("block{i}"),
                    id: Id::new("".to_string()),
                    arguments: ParsedArguments {
                        args: vec![],
                        kwargs: vec![],
                    },
                    inline_text: QuotedString::new("".to_string(), false),
                    line_index: Some(i as usize),
                    is_void: false,
                },
            };
            context.handle(event);

            // Each block should start with a clean scope
            assert_eq!(
                context.visible_scoped_items().len(),
                0,
                "Block {i} should start with empty scope"
            );

            // Add a variable specific to this block
            context.put_scoped(format!("var{i}"), json!(format!("value{}", i)));

            // Should only see this block's variable
            assert_eq!(
                context.get(&format!("var{i}")),
                Some(json!(format!("value{}", i)))
            );

            // Should not see previous blocks' variables
            for j in 1..i {
                assert_eq!(
                    context.get(&format!("var{j}")),
                    None,
                    "Block {i} should not see var{j}"
                );
            }
        }
    }

    #[test]
    fn test_nested_scope_inheritance() {
        use crate::events::Event;
        use crate::parsers::wasot::{Id, MetaLine, ParsedArguments, QuotedString};

        let mut context = Context::new();

        // Create a nested structure: parent -> child -> grandchild
        let parent = Event::BlockStarted {
            meta_line: MetaLine {
                level: 1,
                type_name: "parent".to_string(),
                id: Id::new("".to_string()),
                arguments: ParsedArguments {
                    args: vec![],
                    kwargs: vec![],
                },
                inline_text: QuotedString::new("".to_string(), false),
                line_index: Some(0),
                is_void: false,
            },
        };
        context.handle(parent);
        context.put_scoped("parent_var".to_string(), json!("parent_value"));

        let child = Event::BlockStarted {
            meta_line: MetaLine {
                level: 2,
                type_name: "child".to_string(),
                id: Id::new("".to_string()),
                arguments: ParsedArguments {
                    args: vec![],
                    kwargs: vec![],
                },
                inline_text: QuotedString::new("".to_string(), false),
                line_index: Some(1),
                is_void: false,
            },
        };
        context.handle(child);

        // Child should see parent's variable
        assert_eq!(context.get("parent_var"), Some(json!("parent_value")));
        context.put_scoped("child_var".to_string(), json!("child_value"));

        let grandchild = Event::BlockStarted {
            meta_line: MetaLine {
                level: 3,
                type_name: "grandchild".to_string(),
                id: Id::new("".to_string()),
                arguments: ParsedArguments {
                    args: vec![],
                    kwargs: vec![],
                },
                inline_text: QuotedString::new("".to_string(), false),
                line_index: Some(2),
                is_void: false,
            },
        };
        context.handle(grandchild);

        // Grandchild should see both parent's and child's variables
        assert_eq!(context.get("parent_var"), Some(json!("parent_value")));
        assert_eq!(context.get("child_var"), Some(json!("child_value")));
        context.put_scoped("grandchild_var".to_string(), json!("grandchild_value"));

        // Go back to parent level with a sibling
        let sibling = Event::BlockStarted {
            meta_line: MetaLine {
                level: 1,
                type_name: "sibling".to_string(),
                id: Id::new("".to_string()),
                arguments: ParsedArguments {
                    args: vec![],
                    kwargs: vec![],
                },
                inline_text: QuotedString::new("".to_string(), false),
                line_index: Some(3),
                is_void: false,
            },
        };
        context.handle(sibling);

        // Sibling should not see any variables from the previous family
        assert_eq!(context.get("parent_var"), None);
        assert_eq!(context.get("child_var"), None);
        assert_eq!(context.get("grandchild_var"), None);
    }

    #[test]
    fn test_scope_clearing_on_level_change() {
        use crate::events::Event;
        use crate::parsers::wasot::{Id, MetaLine, ParsedArguments, QuotedString};

        let mut context = Context::new();

        // Start at level 1
        context.handle(Event::BlockStarted {
            meta_line: MetaLine {
                level: 1,
                type_name: "level1".to_string(),
                id: Id::new("".to_string()),
                arguments: ParsedArguments {
                    args: vec![],
                    kwargs: vec![],
                },
                inline_text: QuotedString::new("".to_string(), false),
                line_index: Some(0),
                is_void: false,
            },
        });
        context.put_scoped("level1_var".to_string(), json!("value1"));

        // Go to level 2
        context.handle(Event::BlockStarted {
            meta_line: MetaLine {
                level: 2,
                type_name: "level2".to_string(),
                id: Id::new("".to_string()),
                arguments: ParsedArguments {
                    args: vec![],
                    kwargs: vec![],
                },
                inline_text: QuotedString::new("".to_string(), false),
                line_index: Some(1),
                is_void: false,
            },
        });
        context.put_scoped("level2_var".to_string(), json!("value2"));

        // Go to level 3
        context.handle(Event::BlockStarted {
            meta_line: MetaLine {
                level: 3,
                type_name: "level3".to_string(),
                id: Id::new("".to_string()),
                arguments: ParsedArguments {
                    args: vec![],
                    kwargs: vec![],
                },
                inline_text: QuotedString::new("".to_string(), false),
                line_index: Some(2),
                is_void: false,
            },
        });
        context.put_scoped("level3_var".to_string(), json!("value3"));

        // All variables should be visible
        assert_eq!(context.get("level1_var"), Some(json!("value1")));
        assert_eq!(context.get("level2_var"), Some(json!("value2")));
        assert_eq!(context.get("level3_var"), Some(json!("value3")));

        // Jump back to level 1 (should clear level 2 and 3)
        context.handle(Event::BlockStarted {
            meta_line: MetaLine {
                level: 1,
                type_name: "new_level1".to_string(),
                id: Id::new("".to_string()),
                arguments: ParsedArguments {
                    args: vec![],
                    kwargs: vec![],
                },
                inline_text: QuotedString::new("".to_string(), false),
                line_index: Some(3),
                is_void: false,
            },
        });

        // Should not see any previous variables (new sibling at level 1)
        assert_eq!(context.get("level1_var"), None);
        assert_eq!(context.get("level2_var"), None);
        assert_eq!(context.get("level3_var"), None);
    }

    #[test]
    fn test_context_with_tools() {
        use crate::events::Event;
        use crate::tools::{Tool, ToolCallback};

        struct TestTool;
        impl ToolCallback for TestTool {
            fn handle(&self, _event: &Event, _context: Context) {}
            fn as_any(&self) -> &dyn std::any::Any {
                self
            }
        }

        let tool1 = Tool::new(
            "tool1".to_string(),
            vec!["test1".to_string()],
            Box::new(TestTool),
        )
        .unwrap();
        let tool2 = Tool::new(
            "tool2".to_string(),
            vec!["test2".to_string()],
            Box::new(TestTool),
        )
        .unwrap();

        let tools = vec![tool1, tool2];
        let context = Context::with_tools(tools);

        assert_eq!(context.tools().len(), 2);
        let tool_names: Vec<String> = context.tools().iter().map(|t| t.name.clone()).collect();
        assert!(tool_names.contains(&"tool1".to_string()));
        assert!(tool_names.contains(&"tool2".to_string()));
    }

    #[test]
    fn test_put_serializable_error_handling() {
        // Note: NaN and infinity are actually serialized as null by serde_json
        // So we need a truly non-serializable value. We'll test with successful serialization instead.
        let context = Context::new();

        // Test successful serialization of edge cases
        let result = context.put_serializable("infinity".to_string(), f64::INFINITY);
        assert!(result.is_ok());

        // Infinity should be serialized as null
        assert_eq!(context.get("infinity"), Some(json!(null)));

        // Test with normal value
        let result2 = context.put_serializable("normal".to_string(), 42.5);
        assert!(result2.is_ok());
        assert_eq!(context.get("normal"), Some(json!(42.5)));
    }

    #[test]
    fn test_put_scoped_serializable() {
        let context = Context::new();

        #[derive(serde::Serialize, serde::Deserialize, PartialEq, Debug)]
        struct TestStruct {
            name: String,
            value: i32,
        }

        let test_data = TestStruct {
            name: "test".to_string(),
            value: 42,
        };

        // Test successful serialization
        let result = context.put_scoped_serializable("test_struct".to_string(), &test_data);
        assert!(result.is_ok());

        // Should be retrievable as the original type
        let retrieved: Option<TestStruct> = context.get_scoped_as("test_struct");
        assert_eq!(retrieved, Some(test_data));

        // Should also be retrievable as JSON Value
        let as_value = context.get_scoped("test_struct");
        assert!(as_value.is_some());
        if let Some(Value::Object(obj)) = as_value {
            assert_eq!(obj.get("name"), Some(&json!("test")));
            assert_eq!(obj.get("value"), Some(&json!(42)));
        }
    }

    #[test]
    fn test_put_scoped_serializable_edge_cases() {
        let context = Context::new();

        // Test successful serialization of edge cases
        let result = context.put_scoped_serializable("infinity".to_string(), f64::INFINITY);
        assert!(result.is_ok());

        // Infinity should be serialized as null
        assert_eq!(context.get_scoped("infinity"), Some(json!(null)));

        // Test with NaN
        let result2 = context.put_scoped_serializable("nan".to_string(), f64::NAN);
        assert!(result2.is_ok());

        // NaN should be serialized as null
        assert_eq!(context.get_scoped("nan"), Some(json!(null)));
    }

    #[test]
    fn test_get_scoped_as() {
        let context = Context::new();

        // Test with different types
        context.put_scoped("string".to_string(), json!("hello"));
        context.put_scoped("number".to_string(), json!(123));
        context.put_scoped("boolean".to_string(), json!(true));
        context.put_scoped("array".to_string(), json!([1, 2, 3]));

        // Test successful deserialization
        let string_val: Option<String> = context.get_scoped_as("string");
        assert_eq!(string_val, Some("hello".to_string()));

        let number_val: Option<i32> = context.get_scoped_as("number");
        assert_eq!(number_val, Some(123));

        let bool_val: Option<bool> = context.get_scoped_as("boolean");
        assert_eq!(bool_val, Some(true));

        let array_val: Option<Vec<i32>> = context.get_scoped_as("array");
        assert_eq!(array_val, Some(vec![1, 2, 3]));

        // Test failed deserialization (wrong type)
        let wrong_type: Option<bool> = context.get_scoped_as("string");
        assert_eq!(wrong_type, None);

        // Test non-existent key
        let nonexistent: Option<String> = context.get_scoped_as("nonexistent");
        assert_eq!(nonexistent, None);
    }

    #[test]
    fn test_consumer_handle_direct() {
        use crate::events::Event;
        use crate::parsers::wasot::{Id, MetaLine, ParsedArguments, QuotedString};

        let mut context = Context::new();

        // Test BlockStarted event
        let event = Event::BlockStarted {
            meta_line: MetaLine {
                level: 1,
                type_name: "test".to_string(),
                id: Id::new("".to_string()),
                arguments: ParsedArguments {
                    args: vec![],
                    kwargs: vec![],
                },
                inline_text: QuotedString::new("".to_string(), false),
                line_index: Some(0),
                is_void: false,
            },
        };

        context.handle(event);
        assert_eq!(context.current_depth(), 1);

        // Test BlockFinished event
        let finish_event = Event::BlockFinished;
        context.handle(finish_event);
        // Note: BlockFinished doesn't change depth in current implementation
        assert_eq!(context.current_depth(), 1);
    }

    #[test]
    fn test_tools_edge_cases() {
        use crate::events::Event;
        use crate::tools::{get_global_registry, Tool, ToolCallback};

        struct EdgeCaseTool;
        impl ToolCallback for EdgeCaseTool {
            fn handle(&self, _event: &Event, _context: Context) {}
            fn as_any(&self) -> &dyn std::any::Any {
                self
            }
        }

        let context = Context::new();

        // Test enable_tool with existing tool in global registry
        {
            let global_registry = get_global_registry();
            let mut registry_guard = global_registry.lock().unwrap();
            let test_tool = Tool::new(
                "edge_case_tool".to_string(),
                vec!["edge".to_string()],
                Box::new(EdgeCaseTool),
            )
            .unwrap();
            registry_guard.register(test_tool);
        }

        // Now enable_tool should work
        let result = context.enable_tool("edge_case_tool");
        assert!(result.is_ok());
        assert_eq!(context.tools().len(), 1);
        assert_eq!(context.tools()[0].name, "edge_case_tool");

        // Test enabling the same tool twice
        let result2 = context.enable_tool("edge_case_tool");
        assert!(result2.is_err());
        assert_eq!(
            result2.unwrap_err(),
            "Tool 'edge_case_tool' is already enabled"
        );

        // Should still have only one tool
        assert_eq!(context.tools().len(), 1);
    }

    #[test]
    fn test_scoped_inheritance_with_multiple_levels() {
        let context = Context::new();

        // Test inheritance across multiple scope levels
        context.put_scoped("level0".to_string(), json!("root"));

        context.push_scope(); // level 1
        context.put_scoped("level1".to_string(), json!("first"));
        assert_eq!(context.get_scoped("level0"), Some(json!("root")));
        assert_eq!(context.get_scoped("level1"), Some(json!("first")));

        context.push_scope(); // level 2
        context.put_scoped("level2".to_string(), json!("second"));
        assert_eq!(context.get_scoped("level0"), Some(json!("root")));
        assert_eq!(context.get_scoped("level1"), Some(json!("first")));
        assert_eq!(context.get_scoped("level2"), Some(json!("second")));

        context.push_scope(); // level 3
        context.put_scoped("level3".to_string(), json!("third"));

        // All levels should be visible
        assert_eq!(context.get_scoped("level0"), Some(json!("root")));
        assert_eq!(context.get_scoped("level1"), Some(json!("first")));
        assert_eq!(context.get_scoped("level2"), Some(json!("second")));
        assert_eq!(context.get_scoped("level3"), Some(json!("third")));

        // Pop back to level 1
        context.pop_scope(); // level 2
        context.pop_scope(); // level 1

        // Should only see level 0 and 1
        assert_eq!(context.get_scoped("level0"), Some(json!("root")));
        assert_eq!(context.get_scoped("level1"), Some(json!("first")));
        assert_eq!(context.get_scoped("level2"), None);
        assert_eq!(context.get_scoped("level3"), None);
    }

    #[test]
    fn test_context_mixed_global_scoped_interactions() {
        let context = Context::new();

        // Test interaction between global and scoped variables with same key
        context.put("shared_key".to_string(), json!("global_value"));

        // Scoped should override global
        context.put_scoped("shared_key".to_string(), json!("scoped_value"));
        assert_eq!(context.get("shared_key"), Some(json!("scoped_value")));

        // Push new scope and shadow again
        context.push_scope();
        context.put_scoped("shared_key".to_string(), json!("nested_scoped"));
        assert_eq!(context.get("shared_key"), Some(json!("nested_scoped")));

        // Clear current scope
        context.clear_current_scope();

        // Should fall back to parent scope
        assert_eq!(context.get("shared_key"), Some(json!("scoped_value")));

        // Pop scope
        context.pop_scope();

        // Clear root scope
        context.clear_current_scope();

        // Should fall back to global
        assert_eq!(context.get("shared_key"), Some(json!("global_value")));
    }

    #[test]
    fn test_context_depth_management() {
        let context = Context::new();
        assert_eq!(context.current_depth(), 0);

        // Push multiple scopes
        context.push_scope();
        assert_eq!(context.current_depth(), 1);

        context.push_scope();
        assert_eq!(context.current_depth(), 2);

        context.push_scope();
        assert_eq!(context.current_depth(), 3);

        // Pop back down
        context.pop_scope();
        assert_eq!(context.current_depth(), 2);

        context.pop_scope();
        assert_eq!(context.current_depth(), 1);

        context.pop_scope();
        assert_eq!(context.current_depth(), 0);

        // Try to pop below 0 (should be safe)
        context.pop_scope();
        assert_eq!(context.current_depth(), 0);
    }

    #[test]
    fn test_scope_expansion_on_put() {
        let context = Context::new();

        // Manually set depth to test scope expansion
        context.push_scope();
        context.push_scope();
        assert_eq!(context.current_depth(), 2);

        // Put scoped value at current depth
        context.put_scoped("test_expand".to_string(), json!("test_value"));

        // Should be able to retrieve it
        assert_eq!(context.get_scoped("test_expand"), Some(json!("test_value")));

        // Test with serializable version too
        #[derive(serde::Serialize)]
        struct TestData {
            value: i32,
        }

        let data = TestData { value: 42 };
        let result = context.put_scoped_serializable("test_expand_ser".to_string(), data);
        assert!(result.is_ok());

        let retrieved_value = context.get_scoped("test_expand_ser");
        assert!(retrieved_value.is_some());
    }

    #[test]
    fn test_text_finished_event_handling() {
        use crate::events::Event;

        let mut context = Context::new();

        // TextFinished events should not affect scope
        let initial_depth = context.current_depth();

        let event = Event::TextFinished {
            lines: vec!["test line".to_string()],
            links: vec![],
            footnotes: vec![],
        };

        context.handle(event);
        assert_eq!(context.current_depth(), initial_depth);
    }

    #[test]
    fn test_block_level_tracking() {
        use crate::events::Event;
        use crate::parsers::wasot::{Id, MetaLine, ParsedArguments, QuotedString};

        let mut context = Context::new();

        // Test initial state from level 0 to level 1
        let event = Event::BlockStarted {
            meta_line: MetaLine {
                level: 1,
                type_name: "first_block".to_string(),
                id: Id::new("".to_string()),
                arguments: ParsedArguments {
                    args: vec![],
                    kwargs: vec![],
                },
                inline_text: QuotedString::new("".to_string(), false),
                line_index: Some(0),
                is_void: false,
            },
        };
        context.handle(event);

        // Should have increased depth
        assert_eq!(context.current_depth(), 1);

        // Add a variable
        context.put_scoped("level1_var".to_string(), json!("level1_value"));

        // Test case where new level equals old level (sibling blocks)
        let sibling_event = Event::BlockStarted {
            meta_line: MetaLine {
                level: 1, // Same level as before
                type_name: "sibling_block".to_string(),
                id: Id::new("".to_string()),
                arguments: ParsedArguments {
                    args: vec![],
                    kwargs: vec![],
                },
                inline_text: QuotedString::new("".to_string(), false),
                line_index: Some(1),
                is_void: false,
            },
        };
        context.handle(sibling_event);

        // Variable from previous sibling should be cleared
        assert_eq!(context.get_scoped("level1_var"), None);
    }

    #[test]
    fn test_pop_scope_with_no_scope_to_clear() {
        let context = Context::new();

        // Push a few scopes
        context.push_scope();
        context.push_scope();

        // Clear should work even if scope is empty
        context.pop_scope();
        context.pop_scope();

        // Now at root level - pop_scope should be safe
        context.pop_scope(); // Should not panic or error

        assert_eq!(context.current_depth(), 0);
    }

    #[test]
    fn test_clear_current_scope_at_various_levels() {
        let context = Context::new();

        // Test clearing at root level
        context.put_scoped("root_var".to_string(), json!("root"));
        context.clear_current_scope();
        assert_eq!(context.get_scoped("root_var"), None);

        // Test clearing at deeper levels
        context.push_scope();
        context.put_scoped("level1_var".to_string(), json!("level1"));

        context.push_scope();
        context.put_scoped("level2_var".to_string(), json!("level2"));

        // Clear level 2
        context.clear_current_scope();
        assert_eq!(context.get_scoped("level2_var"), None);
        assert_eq!(context.get_scoped("level1_var"), Some(json!("level1"))); // Should still exist

        // Clear level 1
        context.pop_scope();
        context.clear_current_scope();
        assert_eq!(context.get_scoped("level1_var"), None);
    }

    #[test]
    fn test_get_operations_with_edge_cases() {
        let context = Context::new();

        // Test get with no scoped items vector
        assert_eq!(context.get("nonexistent"), None);
        assert_eq!(context.get_scoped("nonexistent"), None);

        // Test with depth beyond available scopes
        context.push_scope();
        context.push_scope();
        context.push_scope();

        // Try to get from a level that doesn't have data
        assert_eq!(context.get_scoped("missing"), None);

        // Add data at current level and verify lookup chain
        context.put_scoped("deep_var".to_string(), json!("deep_value"));

        // Should find it at current level
        assert_eq!(context.get_scoped("deep_var"), Some(json!("deep_value")));
        assert_eq!(context.get("deep_var"), Some(json!("deep_value")));
    }
}
