"""`docs/get-started/first-steps.md`: every claim the page makes, proved against the real SDK."""

import pytest
from inline_snapshot import snapshot
from mcp_types import (
    PromptArgument,
    PromptMessage,
    TextContent,
    TextResourceContents,
)

from docs_src.first_steps import tutorial001
from mcp import Client
from mcp.server import MCPServer

# See test_index.py for why this is a per-module mark and not a conftest hook.
pytestmark = [pytest.mark.anyio, pytest.mark.filterwarnings("error::mcp.MCPDeprecationWarning")]


async def test_each_decorator_registers_one_primitive() -> None:
    """tutorial001: name, description and schema all come from the decorated function."""
    async with Client(tutorial001.mcp) as client:
        (tool,) = (await client.list_tools()).tools
        assert tool.name == "add"
        assert tool.description == "Add two numbers."
        assert tool.input_schema == snapshot(
            {
                "type": "object",
                "properties": {
                    "a": {"title": "A", "type": "integer"},
                    "b": {"title": "B", "type": "integer"},
                },
                "required": ["a", "b"],
                "title": "addArguments",
            }
        )

        (template,) = (await client.list_resource_templates()).resource_templates
        assert template.name == "greeting"
        assert template.uri_template == "greeting://{name}"
        assert template.description == "Greet someone by name."

        (prompt,) = (await client.list_prompts()).prompts
        assert prompt.name == "summarize"
        assert prompt.description == "Summarize a piece of text in one sentence."
        assert prompt.arguments == [PromptArgument(name="text", required=True)]


async def test_call_the_tool() -> None:
    """tutorial001: the Inspector walkthrough. `add` with 1 and 2 answers 3."""
    async with Client(tutorial001.mcp) as client:
        result = await client.call_tool("add", {"a": 1, "b": 2})
        assert not result.is_error
        assert result.content == [TextContent(type="text", text="3")]
        assert result.structured_content == {"result": 3}


async def test_templated_resource_is_a_template_not_a_resource() -> None:
    """tutorial001: a `{param}` in the URI means the concrete-resource list stays empty."""
    async with Client(tutorial001.mcp) as client:
        assert (await client.list_resources()).resources == []


async def test_read_the_resource_template() -> None:
    """tutorial001: supplying a `name` reads the template as a concrete resource."""
    async with Client(tutorial001.mcp) as client:
        result = await client.read_resource("greeting://World")
        assert result.contents == [
            TextResourceContents(uri="greeting://World", mime_type="text/plain", text="Hello, World!")
        ]


async def test_get_the_prompt() -> None:
    """tutorial001: the returned string becomes a single user message."""
    async with Client(tutorial001.mcp) as client:
        result = await client.get_prompt("summarize", {"text": "MCP is a protocol."})
        rendered = "Summarize the following text in one sentence:\n\nMCP is a protocol."
        assert result.messages == [PromptMessage(role="user", content=TextContent(type="text", text=rendered))]


async def test_the_three_primitive_capabilities_are_always_declared() -> None:
    """tutorial001: `MCPServer` always declares tools/resources/prompts; only `completions` follows your code.

    An `MCPServer` with nothing registered declares the same three, which is why the
    page ties registration to the *optional* capabilities only.
    """
    async with Client(tutorial001.mcp) as client:
        declared = client.server_capabilities
        # The exact dictionary the page prints from `model_dump(exclude_none=True)`.
        assert declared.model_dump(exclude_none=True) == snapshot(
            {
                "prompts": {"list_changed": True},
                "resources": {"subscribe": True, "list_changed": True},
                "tools": {"list_changed": True},
            }
        )
    async with Client(MCPServer("Empty")) as client:
        assert client.server_capabilities == declared
