import pytest

from fastmcp import Client
from fastmcp.exceptions import ToolError
from pydantic import AnyUrl
from starlette.requests import Request


@pytest.mark.asyncio
async def test_read_object_list(server, mcp, client):
    """Test read_object_list tool."""
    result = await client.call_tool(
        "read_object_list",
        {"host": server.host, "port": server.port, "instance": 1000},
    )
    assert len(result.content) == 1
    assert "device" in result.content[0].text
    assert len(result.structured_content["result"]) == 4


@pytest.mark.asyncio
@pytest.mark.parametrize(
    "prop,expected",
    [
        ("analogValue/1/presentValue", "5.0"),
        ("binaryValue/1/presentValue", "active"),
    ],
)
async def test_read_property(server, mcp, client, prop, expected):
    """Test read_property resource."""
    result = await client.read_resource(
        AnyUrl(f"udp://{server.host}:{server.port}/{prop}")
    )
    assert len(result) == 1
    assert result[0].text == expected


@pytest.mark.asyncio
async def test_write_property(server, mcp, client):
    """Test write_property tool."""
    result = await client.call_tool(
        "write_property",
        {
            "host": server.host,
            "port": server.port,
            "obj": "analogValue,1",
            "prop": "presentValue",
            "data": "11",
        },
    )
    assert len(result.content) == 1
    assert "succedeed" in result.content[0].text


@pytest.mark.asyncio
async def test_who_is(server, mcp, client):
    """Test who_is tool."""
    result = await client.call_tool(
        "who_is",
        {
            "low": 999,
            "high": 1001,
        },
    )
    assert not result.is_error


@pytest.mark.asyncio
async def test_who_is_error(server, mcp_error):
    """Test who_is tool error condition."""
    async with Client(mcp_error) as client:
        with pytest.raises(ToolError) as ex:
            result = await client.call_tool(
                "who_is",
                {
                    "low": 999,
                    "high": 1001,
                },
            )
            assert result.is_error
            assert "who_is_failed" in str(ex.value)


@pytest.mark.asyncio
async def test_who_has(server, mcp, client):
    """Test who_has tool."""
    result = await client.call_tool(
        "who_has",
        {"low": 999, "high": 1001, "obj": "analogValue,1"},
    )
    assert not result.is_error


@pytest.mark.asyncio
async def test_who_has_error(server, mcp_error):
    """Test who_has tool error condition."""
    async with Client(mcp_error) as client:
        with pytest.raises(ToolError) as ex:
            result = await client.call_tool(
                "who_has",
                {"low": 999, "high": 1001, "obj": "analogValue,1"},
            )
            assert result.is_error
            assert "who_has_failed" in str(ex.value)


@pytest.mark.asyncio
async def test_help_prompt(mcp, client):
    """Test help prompt."""
    result = await client.get_prompt("bacnet_help", {})
    assert len(result.messages) == 5


@pytest.mark.asyncio
async def test_error_prompt(mcp, client):
    """Test error prompt."""
    result = await client.get_prompt("bacnet_error", {"error": "Could not read data"})
    assert len(result.messages) == 2


@pytest.mark.asyncio
async def test_health_check(mcp):
    response = await mcp.health_check(
        Request(
            {
                "type": "http",
                "method": "GET",
                "path": "/health",
                "headers": [],
            }
        )
    )
    assert response.status_code == 200
