"""Unit tests for PKB tools via the in-memory MCP client/server harness."""

from __future__ import annotations

import pytest

from mcp.shared.memory import create_connected_server_and_client_session

from pkb import tools as pkb_tools
from pkb.server import mcp


@pytest.fixture
def fresh_notes(monkeypatch):
    """Each test gets its own copy of the seed notes so writes don't leak across tests."""
    seed = {"hello": "Hello note body", "todo": "Pick up groceries",
            "ideas": "Build an MCP server tutorial"}
    monkeypatch.setattr(pkb_tools, "NOTES", dict(seed))
    return seed


@pytest.mark.asyncio
async def test_echo_round_trip():
    async with create_connected_server_and_client_session(mcp._mcp_server) as client:
        result = await client.call_tool("echo", {"text": "hello world"})
        assert result.content[0].text == "hello world"
        assert result.isError is False


@pytest.mark.asyncio
async def test_search_returns_known_titles(fresh_notes):
    async with create_connected_server_and_client_session(mcp._mcp_server) as client:
        result = await client.call_tool("search", {"args": {"query": "hello", "limit": 5}})
        # search returns a list[str] of titles; the client wraps it in a TextContent
        # whose .text is the JSON-encoded list.
        assert "hello" in result.content[0].text


@pytest.mark.asyncio
async def test_fetch_known_id(fresh_notes):
    async with create_connected_server_and_client_session(mcp._mcp_server) as client:
        result = await client.call_tool("fetch", {"id": "hello"})
        assert "Hello note body" in result.content[0].text
        assert result.isError is False


@pytest.mark.asyncio
async def test_fetch_unknown_id_is_error(fresh_notes):
    async with create_connected_server_and_client_session(mcp._mcp_server) as client:
        result = await client.call_tool("fetch", {"id": "no-such-note"})
        assert result.isError is True
        assert "unknown note id" in result.content[0].text


@pytest.mark.asyncio
async def test_write_then_fetch(fresh_notes):
    async with create_connected_server_and_client_session(mcp._mcp_server) as client:
        written = await client.call_tool(
            "write",
            {"args": {"title": "lab10", "body": "from L10 unit test"}},
        )
        assert "saved: lab10" in written.content[0].text

        fetched = await client.call_tool("fetch", {"id": "lab10"})
        assert "from L10 unit test" in fetched.content[0].text


@pytest.mark.asyncio
async def test_summarize_uses_sampling_helper(monkeypatch, fresh_notes):
    """Patch the sampling-dependent helper so the test doesn't need a real LLM.

    Note: server.py imports `summarize_via_sampling` by name, so the patch must
    target the symbol on the `pkb.server` module, not on `pkb.tools`. Patching
    `pkb.tools.summarize_via_sampling` would not affect the reference held by
    the `@mcp.tool()`-decorated wrapper.
    """
    from pkb import server as pkb_server

    async def fake(note_id, ctx):
        return f"SUMMARY OF {note_id}"
    monkeypatch.setattr(pkb_server, "summarize_via_sampling", fake)

    async with create_connected_server_and_client_session(mcp._mcp_server) as client:
        result = await client.call_tool("summarize", {"id": "hello"})
        assert result.content[0].text == "SUMMARY OF hello"
