"""
Farnsworth MCP Server Tests

Tests for Claude Code integration via MCP:
- Tool registration and execution
- Resource serving
- Memory operations through MCP
- Agent delegation through MCP
- Evolution feedback through MCP
"""

import asyncio
import json
import pytest
from unittest.mock import AsyncMock, MagicMock, patch


@pytest.fixture
def event_loop():
    """Create event loop for async tests."""
    loop = asyncio.new_event_loop()
    yield loop
    loop.close()


class TestMCPServerCreation:
    """Tests for MCP server initialization."""

    def test_server_creation(self):
        """Test creating the MCP server."""
        # Mock the MCP library
        with patch.dict("sys.modules", {"mcp": MagicMock(), "mcp.server": MagicMock(), "mcp.types": MagicMock()}):
            from farnsworth.mcp_server.server import FarnsworthMCPServer

            server = FarnsworthMCPServer(data_dir="./test_data")

            assert server is not None
            assert server.data_dir.exists() or True  # May not create in test

    @pytest.mark.asyncio
    async def test_server_initialization(self):
        """Test initializing Farnsworth components."""
        with patch.dict("sys.modules", {"mcp": MagicMock(), "mcp.server": MagicMock(), "mcp.types": MagicMock()}):
            from farnsworth.mcp_server.server import FarnsworthMCPServer

            server = FarnsworthMCPServer()

            # Mock the component initialization
            server._memory_system = MagicMock()
            server._swarm_orchestrator = MagicMock()
            server._fitness_tracker = MagicMock()

            assert server._memory_system is not None


class TestMCPTools:
    """Tests for MCP tool implementations."""

    @pytest.mark.asyncio
    async def test_remember_tool(self):
        """Test the farnsworth_remember tool."""
        with patch.dict("sys.modules", {"mcp": MagicMock(), "mcp.server": MagicMock(), "mcp.types": MagicMock()}):
            from farnsworth.mcp_server.server import FarnsworthMCPServer

            server = FarnsworthMCPServer()

            # Mock memory system
            server._memory_system = AsyncMock()
            server._memory_system.remember = AsyncMock(return_value="memory_123")

            result = await server.remember(
                content="User prefers detailed explanations",
                tags=["preference", "communication"],
                importance=0.8,
            )

            assert result["success"] is True
            assert "memory_id" in result

    @pytest.mark.asyncio
    async def test_recall_tool(self):
        """Test the farnsworth_recall tool."""
        with patch.dict("sys.modules", {"mcp": MagicMock(), "mcp.server": MagicMock(), "mcp.types": MagicMock()}):
            from farnsworth.mcp_server.server import FarnsworthMCPServer

            server = FarnsworthMCPServer()

            # Mock memory system with results
            mock_result = MagicMock()
            mock_result.content = "User prefers detailed explanations"
            mock_result.source = "archival"
            mock_result.score = 0.95

            server._memory_system = AsyncMock()
            server._memory_system.recall = AsyncMock(return_value=[mock_result])

            result = await server.recall(
                query="What are the user's communication preferences?",
                limit=5,
            )

            assert result["success"] is True
            assert result["count"] > 0
            assert "memories" in result

    @pytest.mark.asyncio
    async def test_delegate_tool(self):
        """Test the farnsworth_delegate tool."""
        with patch.dict("sys.modules", {"mcp": MagicMock(), "mcp.server": MagicMock(), "mcp.types": MagicMock()}):
            from farnsworth.mcp_server.server import FarnsworthMCPServer

            server = FarnsworthMCPServer()

            # Mock swarm orchestrator
            mock_result = MagicMock()
            mock_result.success = True
            mock_result.output = "Generated code: def hello(): print('Hello')"
            mock_result.confidence = 0.9
            mock_result.tokens_used = 150
            mock_result.execution_time = 1.5

            server._swarm_orchestrator = AsyncMock()
            server._swarm_orchestrator.submit_task = AsyncMock(return_value="task_123")
            server._swarm_orchestrator.wait_for_task = AsyncMock(return_value=mock_result)

            server._fitness_tracker = MagicMock()
            server._fitness_tracker.record_task_outcome = MagicMock()

            result = await server.delegate(
                task="Write a hello world function in Python",
                agent_type="code",
            )

            assert result["success"] is True
            assert "output" in result

    @pytest.mark.asyncio
    async def test_evolve_tool(self):
        """Test the farnsworth_evolve tool."""
        with patch.dict("sys.modules", {"mcp": MagicMock(), "mcp.server": MagicMock(), "mcp.types": MagicMock()}):
            from farnsworth.mcp_server.server import FarnsworthMCPServer

            server = FarnsworthMCPServer()

            server._fitness_tracker = MagicMock()
            server._fitness_tracker.record = MagicMock()

            server._memory_system = AsyncMock()
            server._memory_system.remember = AsyncMock(return_value="feedback_123")

            result = await server.evolve(
                feedback="Great response! Very helpful and detailed.",
            )

            assert result["success"] is True
            assert result["sentiment"] == "positive"

    @pytest.mark.asyncio
    async def test_status_tool(self):
        """Test the farnsworth_status tool."""
        with patch.dict("sys.modules", {"mcp": MagicMock(), "mcp.server": MagicMock(), "mcp.types": MagicMock()}):
            from farnsworth.mcp_server.server import FarnsworthMCPServer

            server = FarnsworthMCPServer()

            server._memory_system = MagicMock()
            server._memory_system.get_stats = MagicMock(return_value={"memories": 100})

            server._swarm_orchestrator = MagicMock()
            server._swarm_orchestrator.get_swarm_status = MagicMock(return_value={"agents": 3})

            server._fitness_tracker = MagicMock()
            server._fitness_tracker.get_stats = MagicMock(return_value={"fitness": 0.87})

            result = await server.status()

            assert result["success"] is True
            assert "memory" in result
            assert "agents" in result
            assert "evolution" in result


class TestMCPResources:
    """Tests for MCP resource implementations."""

    @pytest.mark.asyncio
    async def test_recent_memories_resource(self):
        """Test the farnsworth://memory/recent resource."""
        with patch.dict("sys.modules", {"mcp": MagicMock(), "mcp.server": MagicMock(), "mcp.types": MagicMock()}):
            from farnsworth.mcp_server.server import FarnsworthMCPServer

            server = FarnsworthMCPServer()

            server._memory_system = MagicMock()
            server._memory_system.get_context = MagicMock(return_value="Recent context...")

            content = await server.get_recent_memories()

            assert content is not None
            assert len(content) > 0

    @pytest.mark.asyncio
    async def test_knowledge_graph_resource(self):
        """Test the farnsworth://memory/graph resource."""
        with patch.dict("sys.modules", {"mcp": MagicMock(), "mcp.server": MagicMock(), "mcp.types": MagicMock()}):
            from farnsworth.mcp_server.server import FarnsworthMCPServer

            server = FarnsworthMCPServer()

            server._memory_system = MagicMock()
            server._memory_system.knowledge_graph = MagicMock()
            server._memory_system.knowledge_graph.get_stats = MagicMock(
                return_value={"entities": 50, "relationships": 120}
            )

            content = await server.get_knowledge_graph()

            assert content is not None
            data = json.loads(content)
            assert "entities" in data

    @pytest.mark.asyncio
    async def test_active_agents_resource(self):
        """Test the farnsworth://agents/active resource."""
        with patch.dict("sys.modules", {"mcp": MagicMock(), "mcp.server": MagicMock(), "mcp.types": MagicMock()}):
            from farnsworth.mcp_server.server import FarnsworthMCPServer

            server = FarnsworthMCPServer()

            server._swarm_orchestrator = MagicMock()
            server._swarm_orchestrator.get_swarm_status = MagicMock(
                return_value={"active_agents": 2, "pending_tasks": 1}
            )

            content = await server.get_active_agents()

            assert content is not None
            data = json.loads(content)
            assert "active_agents" in data

    @pytest.mark.asyncio
    async def test_fitness_metrics_resource(self):
        """Test the farnsworth://evolution/fitness resource."""
        with patch.dict("sys.modules", {"mcp": MagicMock(), "mcp.server": MagicMock(), "mcp.types": MagicMock()}):
            from farnsworth.mcp_server.server import FarnsworthMCPServer

            server = FarnsworthMCPServer()

            server._fitness_tracker = MagicMock()
            server._fitness_tracker.get_stats = MagicMock(
                return_value={"fitness": 0.87, "trend": 0.02}
            )

            content = await server.get_fitness_metrics()

            assert content is not None
            data = json.loads(content)
            assert "fitness" in data


class TestMemoryTools:
    """Tests for advanced memory tool implementations."""

    @pytest.mark.asyncio
    async def test_remember_with_context(self):
        """Test remembering with additional context."""
        from farnsworth.mcp_server.memory_tools import MemoryTools

        mock_memory = AsyncMock()
        mock_memory.remember = AsyncMock(return_value="mem_123")

        tools = MemoryTools(memory_system=mock_memory)

        result = await tools.remember_with_context(
            content="Important fact",
            tags=["important"],
            importance=0.9,
            context={"source": "user_input"},
            extract_entities=True,
        )

        assert result.success is True
        assert "memory_id" in result.data

    @pytest.mark.asyncio
    async def test_advanced_recall(self):
        """Test advanced memory search with filters."""
        from farnsworth.mcp_server.memory_tools import MemoryTools

        mock_result = MagicMock()
        mock_result.content = "Test content"
        mock_result.source = "archival"
        mock_result.score = 0.9
        mock_result.metadata = {"tags": ["test"]}

        mock_memory = AsyncMock()
        mock_memory.recall = AsyncMock(return_value=[mock_result])

        tools = MemoryTools(memory_system=mock_memory)

        result = await tools.advanced_recall(
            query="test query",
            limit=10,
            min_score=0.5,
            tags_filter=["test"],
        )

        assert result.success is True
        assert result.data["count"] > 0

    @pytest.mark.asyncio
    async def test_knowledge_graph_query(self):
        """Test querying the knowledge graph."""
        from farnsworth.mcp_server.memory_tools import MemoryTools

        mock_query_result = MagicMock()
        mock_query_result.entities = []
        mock_query_result.relationships = []
        mock_query_result.paths = []

        mock_memory = MagicMock()
        mock_memory.knowledge_graph = AsyncMock()
        mock_memory.knowledge_graph.query = AsyncMock(return_value=mock_query_result)

        tools = MemoryTools(memory_system=mock_memory)

        result = await tools.query_knowledge_graph(
            query="relationships",
            max_entities=10,
            max_hops=2,
        )

        assert result.success is True


class TestAgentTools:
    """Tests for agent tool implementations."""

    @pytest.mark.asyncio
    async def test_delegate_task(self):
        """Test delegating a task to an agent."""
        from farnsworth.mcp_server.agent_tools import AgentTools

        mock_agent = AsyncMock()
        mock_agent.execute = AsyncMock(return_value=MagicMock(
            success=True,
            output="Result",
            confidence=0.9,
            metadata={},
        ))
        mock_agent.agent_id = "agent_123"

        mock_swarm = MagicMock()
        mock_swarm.spawn_agent = AsyncMock(return_value=mock_agent)
        mock_swarm.state = MagicMock()
        mock_swarm.state.active_agents = {}

        tools = AgentTools(swarm_orchestrator=mock_swarm)

        result = await tools.delegate_task(
            task="Write a function",
            agent_type="code",
            context={},
        )

        assert result.success is True

    @pytest.mark.asyncio
    async def test_list_available_agents(self):
        """Test listing available agents."""
        from farnsworth.mcp_server.agent_tools import AgentTools

        mock_swarm = MagicMock()
        mock_swarm.state = MagicMock()
        mock_swarm.state.active_agents = {}
        mock_swarm.max_concurrent = 5

        tools = AgentTools(swarm_orchestrator=mock_swarm)

        result = await tools.list_available_agents()

        assert result.success is True
        assert "agent_types" in result.data


class TestEvolutionTools:
    """Tests for evolution tool implementations."""

    @pytest.mark.asyncio
    async def test_record_feedback(self):
        """Test recording user feedback."""
        from farnsworth.mcp_server.evolution_tools import EvolutionTools

        mock_fitness = MagicMock()
        mock_fitness.record = MagicMock()
        mock_fitness.get_weighted_fitness = MagicMock(return_value=0.85)

        tools = EvolutionTools(fitness_tracker=mock_fitness)

        result = await tools.record_feedback(
            feedback_type="satisfaction",
            value=0.9,
            context={"task": "code_generation"},
        )

        assert result.success is True
        assert "recorded" in result.data

    @pytest.mark.asyncio
    async def test_get_fitness_metrics(self):
        """Test getting fitness metrics."""
        from farnsworth.mcp_server.evolution_tools import EvolutionTools

        mock_fitness = MagicMock()
        mock_fitness.get_current_fitness = MagicMock(return_value={"task_success": 0.9})
        mock_fitness.get_weighted_fitness = MagicMock(return_value=0.85)
        mock_fitness.get_stats = MagicMock(return_value={
            "current_fitness": {"task_success": 0.9},
            "trends": {},
            "sample_counts": {},
        })

        tools = EvolutionTools(fitness_tracker=mock_fitness)

        result = await tools.get_fitness_metrics()

        assert result.success is True
        assert "current_fitness" in result.data

    @pytest.mark.asyncio
    async def test_get_improvement_suggestions(self):
        """Test getting improvement suggestions."""
        from farnsworth.mcp_server.evolution_tools import EvolutionTools

        mock_fitness = MagicMock()
        mock_fitness.get_current_fitness = MagicMock(return_value={
            "task_success": 0.6,  # Below threshold
            "efficiency": 0.4,    # Below threshold
            "user_satisfaction": 0.5,  # Below threshold
        })
        mock_fitness.get_trend = MagicMock(return_value=-0.05)

        tools = EvolutionTools(fitness_tracker=mock_fitness)

        result = await tools.get_improvement_suggestions()

        assert result.success is True
        assert len(result.data["suggestions"]) > 0


class TestClaudeIntegration:
    """Tests specific to Claude Code integration scenarios."""

    @pytest.mark.asyncio
    async def test_session_memory_persistence(self):
        """Test that memories persist across 'sessions' (tool calls)."""
        with patch.dict("sys.modules", {"mcp": MagicMock(), "mcp.server": MagicMock(), "mcp.types": MagicMock()}):
            from farnsworth.mcp_server.server import FarnsworthMCPServer

            server = FarnsworthMCPServer()

            # Simulate a memory store
            stored_memories = {}

            async def mock_remember(content, **kwargs):
                mem_id = f"mem_{len(stored_memories)}"
                stored_memories[mem_id] = content
                return mem_id

            async def mock_recall(query, **kwargs):
                results = []
                for mem_id, content in stored_memories.items():
                    if query.lower() in content.lower():
                        result = MagicMock()
                        result.content = content
                        result.source = "archival"
                        result.score = 0.9
                        results.append(result)
                return results

            server._memory_system = AsyncMock()
            server._memory_system.remember = mock_remember
            server._memory_system.recall = mock_recall

            # Session 1: Remember something
            await server.remember(content="User likes Python")

            # Session 2: Should be able to recall it
            result = await server.recall(query="Python")

            assert result["success"] is True
            assert result["count"] > 0
            assert "Python" in result["memories"][0]["content"]

    @pytest.mark.asyncio
    async def test_context_augmentation_flow(self):
        """Test the flow of augmenting Claude's context with memories."""
        with patch.dict("sys.modules", {"mcp": MagicMock(), "mcp.server": MagicMock(), "mcp.types": MagicMock()}):
            from farnsworth.mcp_server.server import FarnsworthMCPServer

            server = FarnsworthMCPServer()

            server._memory_system = MagicMock()
            server._memory_system.get_context = MagicMock(return_value="""
            Recent Context:
            - User is working on a Python project
            - User prefers detailed explanations
            - Previous task: implement sorting algorithm
            """)

            # This is what Claude Code would read before responding
            context = await server.get_recent_memories()

            assert "Python project" in context
            assert "detailed explanations" in context


if __name__ == "__main__":
    pytest.main([__file__, "-v"])
