"""Tests for LangChain integration."""
import pytest
from unittest.mock import Mock, patch, MagicMock

import sys
from pathlib import Path
sys.path.insert(0, str(Path(__file__).parent.parent))


# Skip if LangChain not installed
pytest.importorskip("langchain")


class TestGovernedAgentExecutor:
    """Test GovernedAgentExecutor functionality."""
    
    def test_import(self):
        """Test that GovernedAgentExecutor can be imported."""
        from agendex.integrations.langchain import GovernedAgentExecutor
        assert GovernedAgentExecutor is not None
    
    def test_langchain_available_flag(self):
        """Test that LANGCHAIN_AVAILABLE is True."""
        from agendex.integrations.langchain import LANGCHAIN_AVAILABLE
        assert LANGCHAIN_AVAILABLE is True
    
    def test_tool_wrapping(self):
        """Test that tools are wrapped for governance."""
        from agendex.integrations.langchain import _create_governed_tool
        from agendex import AgendexClient
        from langchain_core.tools import StructuredTool
        
        # Create a test tool
        def my_tool(input: str) -> str:
            return f"Result: {input}"
        
        tool = StructuredTool.from_function(
            name="my_tool",
            func=my_tool,
            description="Test tool",
        )
        
        # Create mock client
        mock_client = Mock(spec=AgendexClient)
        mock_client.invoke = Mock(return_value={"_agendex": "shadow"})
        mock_client.mode = "shadow"
        
        # Create governed tool
        state = {"current_reasoning": None, "on_event": None}
        governed = _create_governed_tool(
            tool=tool,
            agendex=mock_client,
            task="test",
            state=state,
        )
        
        # Test that the governed tool works
        result = governed.invoke({"input": "hello"})
        
        # Client should have been called
        mock_client.invoke.assert_called_once()
        
        # Result should contain original output
        assert "Result: hello" in result


class TestReasoningCapture:
    """Test reasoning capture callback."""
    
    def test_reasoning_capture_on_agent_action(self):
        """Test that reasoning is captured from agent actions."""
        from agendex.integrations.langchain import _ReasoningCapture
        from langchain_core.agents import AgentAction
        
        # Create state dict to capture reasoning
        state = {"current_reasoning": None, "on_event": None}
        callback = _ReasoningCapture(state)
        
        # Simulate agent action
        action = AgentAction(
            tool="test_tool",
            tool_input="input",
            log="Thought: I need to test this\nAction: test_tool",
        )
        
        callback.on_agent_action(action)
        
        # Reasoning should be captured in state
        assert state["current_reasoning"] is not None
        assert "I need to test this" in state["current_reasoning"]
    
    def test_reasoning_capture_with_event_callback(self):
        """Test that reasoning events are emitted."""
        from agendex.integrations.langchain import _ReasoningCapture
        from langchain_core.agents import AgentAction
        
        events = []
        state = {
            "current_reasoning": None,
            "on_event": lambda e: events.append(e),
        }
        callback = _ReasoningCapture(state)
        
        action = AgentAction(
            tool="test_tool",
            tool_input="input",
            log="Thought: Testing event emission",
        )
        
        callback.on_agent_action(action)
        
        # Event should have been emitted
        assert len(events) == 1
        assert events[0]["type"] == "reasoning"
        assert "Testing event emission" in events[0]["content"]
