"""The same notebook against the low-level Server: an explicit bus + ListenHandler."""

from typing import Any

import mcp_types as types

from mcp.server.context import ServerRequestContext
from mcp.server.lowlevel import Server
from mcp.server.subscriptions import (
    InMemorySubscriptionBus,
    ListenHandler,
    ResourceUpdated,
    ToolsListChanged,
)
from stories._hosting import run_server_from_args

EDIT_NOTE_SCHEMA: dict[str, Any] = {
    "type": "object",
    "properties": {"name": {"type": "string"}, "text": {"type": "string"}},
    "required": ["name", "text"],
}
EMPTY_SCHEMA: dict[str, Any] = {"type": "object", "properties": {}}
SEARCH_SCHEMA: dict[str, Any] = {
    "type": "object",
    "properties": {"query": {"type": "string"}},
    "required": ["query"],
}


def build_server() -> Server[Any]:
    # The bus lives wherever your handlers can reach it; the lifespan is the
    # natural home in a bigger app. The closure is enough here.
    bus = InMemorySubscriptionBus()
    notes = {"todo": "buy milk", "journal": "day one"}
    search_enabled = False

    async def list_tools(
        ctx: ServerRequestContext[Any], params: types.PaginatedRequestParams | None
    ) -> types.ListToolsResult:
        tools = [
            types.Tool(name="edit_note", description="Replace a note's text.", input_schema=EDIT_NOTE_SCHEMA),
            types.Tool(name="enable_search", description="Register the search tool.", input_schema=EMPTY_SCHEMA),
        ]
        if search_enabled:
            tools.append(types.Tool(name="search", description="Find notes.", input_schema=SEARCH_SCHEMA))
        return types.ListToolsResult(tools=tools)

    async def call_tool(ctx: ServerRequestContext[Any], params: types.CallToolRequestParams) -> types.CallToolResult:
        nonlocal search_enabled
        args = params.arguments or {}
        if params.name == "edit_note":
            notes[args["name"]] = args["text"]
            await bus.publish(ResourceUpdated(uri=f"note://{args['name']}"))
            return types.CallToolResult(content=[types.TextContent(text="saved")])
        if params.name == "enable_search":
            search_enabled = True
            await bus.publish(ToolsListChanged())
            return types.CallToolResult(content=[types.TextContent(text="search is live")])
        assert params.name == "search" and search_enabled
        matches = [name for name, text in notes.items() if args["query"] in text]
        return types.CallToolResult(content=[types.TextContent(text=", ".join(matches))])

    return Server(
        "subscriptions-example",
        on_list_tools=list_tools,
        on_call_tool=call_tool,
        on_subscriptions_listen=ListenHandler(bus),
    )


if __name__ == "__main__":
    run_server_from_args(build_server)
