"""Unit tests for list_custom_reports MCP tool.

Tests the tool wrapper layer: input validation and error conversion.
"""

from unittest.mock import AsyncMock, MagicMock, patch

import pytest
from fastmcp.exceptions import ToolError

from testio_mcp.tools.list_custom_reports_tool import (
    list_custom_reports as list_custom_reports_tool,
)

# Extract actual function from FastMCP FunctionTool wrapper
list_custom_reports = list_custom_reports_tool.fn  # type: ignore[attr-defined]


def _make_mock_ctx() -> MagicMock:
    """Create a mock Context with server_ctx containing cache."""
    mock_ctx = MagicMock()
    mock_cache = MagicMock()
    mock_cache.customer_id = 1

    # async_session_maker returns an async context manager
    mock_session = AsyncMock()
    mock_cache.async_session_maker.return_value.__aenter__ = AsyncMock(return_value=mock_session)
    mock_cache.async_session_maker.return_value.__aexit__ = AsyncMock(return_value=False)

    mock_ctx.request_context.lifespan_context = {
        "testio_client": MagicMock(),
        "cache": mock_cache,
    }
    return mock_ctx


@pytest.mark.unit
@pytest.mark.asyncio
async def test_rejects_empty_test_ids() -> None:
    """Verify ToolError when test_ids is empty."""
    mock_ctx = _make_mock_ctx()

    with pytest.raises(ToolError, match="test_ids is required"):
        await list_custom_reports(ctx=mock_ctx, test_ids=[])


@pytest.mark.unit
@pytest.mark.asyncio
async def test_delegates_to_service() -> None:
    """Verify tool delegates to CustomReportService.list_reports."""
    mock_ctx = _make_mock_ctx()

    expected_result = {
        "test_ids": [147162],
        "total_reports": 76,
        "reports": [{"bug_id": 1, "title": "Bug 1", "report_fields": {"accuracy": "5"}}],
        "pagination": {"page": 1, "per_page": 100, "total_count": 76, "has_more": False},
    }

    with patch("testio_mcp.tools.list_custom_reports_tool.CustomReportService") as MockService:
        mock_service_instance = AsyncMock()
        mock_service_instance.list_reports.return_value = expected_result
        MockService.return_value = mock_service_instance

        result = await list_custom_reports(
            ctx=mock_ctx,
            test_ids=[147162],
            fields=["accuracy"],
            page=1,
            per_page=50,
        )

    assert result == expected_result
    mock_service_instance.list_reports.assert_called_once_with(
        test_ids=[147162],
        fields=["accuracy"],
        page=1,
        per_page=50,
    )


@pytest.mark.unit
@pytest.mark.asyncio
async def test_converts_exception_to_tool_error() -> None:
    """Verify unexpected exceptions are converted to ToolError."""
    mock_ctx = _make_mock_ctx()

    with patch("testio_mcp.tools.list_custom_reports_tool.CustomReportService") as MockService:
        mock_service_instance = AsyncMock()
        mock_service_instance.list_reports.side_effect = RuntimeError("DB connection lost")
        MockService.return_value = mock_service_instance

        with pytest.raises(ToolError, match="Unexpected error"):
            await list_custom_reports(ctx=mock_ctx, test_ids=[147162])


@pytest.mark.unit
@pytest.mark.asyncio
async def test_parses_string_test_ids() -> None:
    """Verify string test_ids are parsed correctly."""
    mock_ctx = _make_mock_ctx()

    expected_result = {
        "test_ids": [147162, 147163],
        "total_reports": 0,
        "reports": [],
        "pagination": {"page": 1, "per_page": 100, "total_count": 0, "has_more": False},
    }

    with patch("testio_mcp.tools.list_custom_reports_tool.CustomReportService") as MockService:
        mock_service_instance = AsyncMock()
        mock_service_instance.list_reports.return_value = expected_result
        MockService.return_value = mock_service_instance

        result = await list_custom_reports(
            ctx=mock_ctx,
            test_ids="147162,147163",
        )

    assert result == expected_result
    mock_service_instance.list_reports.assert_called_once_with(
        test_ids=[147162, 147163],
        fields=None,
        page=1,
        per_page=100,
    )


@pytest.mark.unit
@pytest.mark.asyncio
async def test_default_pagination() -> None:
    """Verify default pagination parameters."""
    mock_ctx = _make_mock_ctx()

    expected_result = {
        "test_ids": [147162],
        "total_reports": 0,
        "reports": [],
        "pagination": {"page": 1, "per_page": 100, "total_count": 0, "has_more": False},
    }

    with patch("testio_mcp.tools.list_custom_reports_tool.CustomReportService") as MockService:
        mock_service_instance = AsyncMock()
        mock_service_instance.list_reports.return_value = expected_result
        MockService.return_value = mock_service_instance

        await list_custom_reports(ctx=mock_ctx, test_ids=147162)

    mock_service_instance.list_reports.assert_called_once_with(
        test_ids=[147162],
        fields=None,
        page=1,
        per_page=100,
    )
