"""Integration tests for title field functionality."""

import pytest
from mcp_types import Prompt, Resource, ResourceTemplate, Tool, ToolAnnotations

from mcp import Client
from mcp.server.mcpserver import MCPServer
from mcp.server.mcpserver.resources import FunctionResource
from mcp.shared.metadata_utils import get_display_name


@pytest.mark.anyio
async def test_server_name_title_description_version():
    """Test that server title and description are set and retrievable correctly."""
    mcp = MCPServer(
        name="TestServer",
        title="Test Server Title",
        description="This is a test server description.",
        version="1.0",
    )

    assert mcp.title == "Test Server Title"
    assert mcp.description == "This is a test server description."
    assert mcp.version == "1.0"

    # Start server and connect client
    async with Client(mcp) as client:
        assert client.server_info.name == "TestServer"
        assert client.server_info.title == "Test Server Title"
        assert client.server_info.description == "This is a test server description."
        assert client.server_info.version == "1.0"


@pytest.mark.anyio
async def test_tool_title_precedence():
    """Test that tool title precedence works correctly: title > annotations.title > name."""
    # Create server with various tool configurations
    mcp = MCPServer(name="TitleTestServer")

    # Tool with only name
    @mcp.tool(description="Basic tool")
    def basic_tool(message: str) -> str:  # pragma: no cover
        return message

    # Tool with title
    @mcp.tool(description="Tool with title", title="User-Friendly Tool")
    def tool_with_title(message: str) -> str:  # pragma: no cover
        return message

    # Tool with annotations.title (when title is not supported on decorator)
    # We'll need to add this manually after registration
    @mcp.tool(description="Tool with annotations")
    def tool_with_annotations(message: str) -> str:  # pragma: no cover
        return message

    # Tool with both title and annotations.title
    @mcp.tool(description="Tool with both", title="Primary Title")
    def tool_with_both(message: str) -> str:  # pragma: no cover
        return message

    # Start server and connect client
    async with Client(mcp) as client:
        # List tools
        tools_result = await client.list_tools()
        tools = {tool.name: tool for tool in tools_result.tools}

        # Verify basic tool uses name
        assert "basic_tool" in tools
        basic = tools["basic_tool"]
        # Since we haven't implemented get_display_name yet, we'll check the raw fields
        assert basic.title is None
        assert basic.name == "basic_tool"

        # Verify tool with title
        assert "tool_with_title" in tools
        titled = tools["tool_with_title"]
        assert titled.title == "User-Friendly Tool"

        # For now, we'll skip the annotations.title test as it requires modifying
        # the tool after registration, which we'll implement later

        # Verify tool with both uses title over annotations.title
        assert "tool_with_both" in tools
        both = tools["tool_with_both"]
        assert both.title == "Primary Title"


@pytest.mark.anyio
async def test_prompt_title():
    """Test that prompt titles work correctly."""
    mcp = MCPServer(name="PromptTitleServer")

    # Prompt with only name
    @mcp.prompt(description="Basic prompt")
    def basic_prompt(topic: str) -> str:  # pragma: no cover
        return f"Tell me about {topic}"

    # Prompt with title
    @mcp.prompt(description="Titled prompt", title="Ask About Topic")
    def titled_prompt(topic: str) -> str:  # pragma: no cover
        return f"Tell me about {topic}"

    # Start server and connect client
    async with Client(mcp) as client:
        # List prompts
        prompts_result = await client.list_prompts()
        prompts = {prompt.name: prompt for prompt in prompts_result.prompts}

        # Verify basic prompt uses name
        assert "basic_prompt" in prompts
        basic = prompts["basic_prompt"]
        assert basic.title is None
        assert basic.name == "basic_prompt"

        # Verify prompt with title
        assert "titled_prompt" in prompts
        titled = prompts["titled_prompt"]
        assert titled.title == "Ask About Topic"


@pytest.mark.anyio
async def test_resource_title():
    """Test that resource titles work correctly."""
    mcp = MCPServer(name="ResourceTitleServer")

    # Static resource without title
    def get_basic_data() -> str:  # pragma: no cover
        return "Basic data"

    basic_resource = FunctionResource(
        uri="resource://basic",
        name="basic_resource",
        description="Basic resource",
        fn=get_basic_data,
    )
    mcp.add_resource(basic_resource)

    # Static resource with title
    def get_titled_data() -> str:  # pragma: no cover
        return "Titled data"

    titled_resource = FunctionResource(
        uri="resource://titled",
        name="titled_resource",
        title="User-Friendly Resource",
        description="Resource with title",
        fn=get_titled_data,
    )
    mcp.add_resource(titled_resource)

    # Dynamic resource without title
    @mcp.resource("resource://dynamic/{id}")
    def dynamic_resource(id: str) -> str:  # pragma: no cover
        return f"Data for {id}"

    # Dynamic resource with title (when supported)
    @mcp.resource("resource://titled-dynamic/{id}", title="Dynamic Data")
    def titled_dynamic_resource(id: str) -> str:  # pragma: no cover
        return f"Data for {id}"

    # Start server and connect client
    async with Client(mcp) as client:
        # List resources
        resources_result = await client.list_resources()
        resources = {str(res.uri): res for res in resources_result.resources}

        # Verify basic resource uses name
        assert "resource://basic" in resources
        basic = resources["resource://basic"]
        assert basic.title is None
        assert basic.name == "basic_resource"

        # Verify resource with title
        assert "resource://titled" in resources
        titled = resources["resource://titled"]
        assert titled.title == "User-Friendly Resource"

        # List resource templates
        templates_result = await client.list_resource_templates()
        templates = {tpl.uri_template: tpl for tpl in templates_result.resource_templates}

        # Verify dynamic resource template
        assert "resource://dynamic/{id}" in templates
        dynamic = templates["resource://dynamic/{id}"]
        assert dynamic.title is None
        assert dynamic.name == "dynamic_resource"

        # Verify titled dynamic resource template (when supported)
        if "resource://titled-dynamic/{id}" in templates:  # pragma: no branch
            titled_dynamic = templates["resource://titled-dynamic/{id}"]
            assert titled_dynamic.title == "Dynamic Data"


@pytest.mark.anyio
async def test_get_display_name_utility():
    """Test the get_display_name utility function."""

    # Test tool precedence: title > annotations.title > name
    tool_name_only = Tool(name="test_tool", input_schema={})
    assert get_display_name(tool_name_only) == "test_tool"

    tool_with_title = Tool(name="test_tool", title="Test Tool", input_schema={})
    assert get_display_name(tool_with_title) == "Test Tool"

    tool_with_annotations = Tool(name="test_tool", input_schema={}, annotations=ToolAnnotations(title="Annotated Tool"))
    assert get_display_name(tool_with_annotations) == "Annotated Tool"

    tool_with_both = Tool(
        name="test_tool", title="Primary Title", input_schema={}, annotations=ToolAnnotations(title="Secondary Title")
    )
    assert get_display_name(tool_with_both) == "Primary Title"

    # Test other types: title > name
    resource = Resource(uri="file://test", name="test_res")
    assert get_display_name(resource) == "test_res"

    resource_with_title = Resource(uri="file://test", name="test_res", title="Test Resource")
    assert get_display_name(resource_with_title) == "Test Resource"

    prompt = Prompt(name="test_prompt")
    assert get_display_name(prompt) == "test_prompt"

    prompt_with_title = Prompt(name="test_prompt", title="Test Prompt")
    assert get_display_name(prompt_with_title) == "Test Prompt"

    template = ResourceTemplate(uri_template="file://{id}", name="test_template")
    assert get_display_name(template) == "test_template"

    template_with_title = ResourceTemplate(uri_template="file://{id}", name="test_template", title="Test Template")
    assert get_display_name(template_with_title) == "Test Template"
