"""Tests for memory_graph MCP tool."""

import sqlite3
from unittest.mock import MagicMock
import pytest

from neo_cortex.graph import ConceptGraph


@pytest.fixture
def graph():
    conn = sqlite3.connect(":memory:")
    g = ConceptGraph(conn)
    g.add_memory("m1", ["DNS", "OVH", "cert-manager"])
    g.add_memory("m2", ["DNS", "Terraform"])
    g.add_memory("m3", ["cert-manager", "Keel", "Harbor"])
    g.add_memory("m4", ["Keel", "Harbor", "Prometheus"])
    return g


@pytest.fixture
def patched_cortex(graph):
    """Swap _cortex in mcp module for testing, restore after."""
    from neo_cortex import mcp as mcp_module
    original = mcp_module._cortex
    cortex = MagicMock()
    cortex._graph = graph
    mcp_module._cortex = cortex
    yield mcp_module
    mcp_module._cortex = original


class TestMemoryGraphTop:
    @pytest.mark.asyncio
    async def test_top_returns_concepts(self, patched_cortex):
        result = await patched_cortex.memory_graph.fn(action="top", n=3)
        assert "concepts" in result
        assert len(result["concepts"]) == 3
        assert result["concepts"][0]["mentions"] >= result["concepts"][1]["mentions"]


class TestMemoryGraphNeighbors:
    @pytest.mark.asyncio
    async def test_neighbors_returns_connected(self, patched_cortex):
        result = await patched_cortex.memory_graph.fn(action="neighbors", concept="DNS")
        assert "neighbors" in result
        names = [n["concept"] for n in result["neighbors"]]
        assert "OVH" in names
        assert "cert-manager" in names

    @pytest.mark.asyncio
    async def test_neighbors_missing_concept(self, patched_cortex):
        result = await patched_cortex.memory_graph.fn(action="neighbors")
        assert "error" in result


class TestMemoryGraphPath:
    @pytest.mark.asyncio
    async def test_path_found(self, patched_cortex):
        result = await patched_cortex.memory_graph.fn(
            action="path", concept="OVH", to_concept="Prometheus"
        )
        assert "path" in result
        assert result["path"][0] == "OVH"
        assert result["path"][-1] == "Prometheus"

    @pytest.mark.asyncio
    async def test_path_not_found(self, patched_cortex):
        result = await patched_cortex.memory_graph.fn(
            action="path", concept="OVH", to_concept="NONEXISTENT"
        )
        assert result["path"] == []

    @pytest.mark.asyncio
    async def test_path_missing_params(self, patched_cortex):
        result = await patched_cortex.memory_graph.fn(action="path", concept="OVH")
        assert "error" in result


class TestMemoryGraphNeighborhood:
    @pytest.mark.asyncio
    async def test_neighborhood_returns_nodes_and_edges(self, patched_cortex):
        result = await patched_cortex.memory_graph.fn(
            action="neighborhood", concept="DNS", depth=1
        )
        assert "nodes" in result
        assert "edges" in result
        node_names = {n["concept"] for n in result["nodes"]}
        assert "DNS" in node_names

    @pytest.mark.asyncio
    async def test_neighborhood_missing_concept(self, patched_cortex):
        result = await patched_cortex.memory_graph.fn(action="neighborhood")
        assert "error" in result


class TestMemoryGraphErrors:
    @pytest.mark.asyncio
    async def test_invalid_action(self, patched_cortex):
        result = await patched_cortex.memory_graph.fn(action="invalid")
        assert "error" in result

    @pytest.mark.asyncio
    async def test_no_graph_available(self):
        from neo_cortex import mcp as mcp_module
        original = mcp_module._cortex
        cortex = MagicMock()
        cortex._graph = None
        mcp_module._cortex = cortex
        try:
            result = await mcp_module.memory_graph.fn(action="top")
            assert "error" in result
        finally:
            mcp_module._cortex = original
