"""Test log_level parameter support in FastMCP server."""

import asyncio
import socket
from unittest.mock import AsyncMock, patch

from fastmcp import FastMCP


class TestLogLevelParameter:
    """Test that log_level parameter is properly accepted by run methods."""

    async def test_run_stdio_accepts_log_level(self):
        """Test that run_stdio_async accepts log_level parameter."""
        server = FastMCP("TestServer")

        # Mock the stdio_server to avoid actual stdio operations
        with patch("fastmcp.server.mixins.transport.stdio_server") as mock_stdio:
            mock_stdio.return_value.__aenter__ = AsyncMock(
                return_value=(AsyncMock(), AsyncMock())
            )
            mock_stdio.return_value.__aexit__ = AsyncMock()

            # Mock the underlying MCP server run method
            with patch.object(server._mcp_server, "run", new_callable=AsyncMock):
                try:
                    # This should accept the log_level parameter without error
                    await asyncio.wait_for(
                        server.run_stdio_async(log_level="DEBUG", show_banner=False),
                        timeout=0.1,
                    )
                except asyncio.TimeoutError:
                    pass  # Expected since we're mocking

    async def test_run_http_accepts_log_level(self):
        """Test that run_http_async accepts log_level parameter."""
        server = FastMCP("TestServer")

        # Mock uvicorn to avoid actual server start
        with patch(
            "fastmcp.server.mixins.transport.uvicorn.Server"
        ) as mock_server_class:
            mock_instance = mock_server_class.return_value
            mock_instance.serve = AsyncMock()

            # This should accept the log_level parameter without error
            await server.run_http_async(
                log_level="INFO", show_banner=False, host="127.0.0.1", port=8000
            )

            # Verify serve was called
            mock_instance.serve.assert_called_once()

    async def test_run_http_passes_sockets_to_uvicorn(self):
        """Test that run_http_async forwards pre-bound sockets to Uvicorn."""
        server = FastMCP("TestServer")

        with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as sock:
            with patch(
                "fastmcp.server.mixins.transport.uvicorn.Server"
            ) as mock_server_class:
                mock_instance = mock_server_class.return_value
                mock_instance.serve = AsyncMock()

                await server.run_http_async(
                    show_banner=False,
                    host="127.0.0.1",
                    port=8000,
                    sockets=[sock],
                )

                mock_instance.serve.assert_called_once_with(sockets=[sock])

    async def test_run_async_passes_log_level(self):
        """Test that run_async passes log_level to transport methods."""
        server = FastMCP("TestServer")

        # Test stdio transport
        with patch.object(
            server, "run_stdio_async", new_callable=AsyncMock
        ) as mock_stdio:
            await server.run_async(transport="stdio", log_level="WARNING")
            mock_stdio.assert_called_once_with(show_banner=True, log_level="WARNING")

        # Test http transport
        with patch.object(
            server, "run_http_async", new_callable=AsyncMock
        ) as mock_http:
            await server.run_async(transport="http", log_level="ERROR")
            mock_http.assert_called_once_with(
                transport="http", show_banner=True, log_level="ERROR"
            )

    def test_sync_run_accepts_log_level(self):
        """Test that the synchronous run method accepts log_level."""
        server = FastMCP("TestServer")

        with patch.object(server, "run_async", new_callable=AsyncMock):
            # Mock anyio.run to avoid actual async execution
            with patch("anyio.run") as mock_anyio_run:
                server.run(transport="stdio", log_level="CRITICAL")

                # Verify anyio.run was called
                mock_anyio_run.assert_called_once()

                # Get the function that was passed to anyio.run
                called_func = mock_anyio_run.call_args[0][0]

                # The function should be a partial that includes log_level
                assert hasattr(called_func, "keywords")
                assert called_func.keywords.get("log_level") == "CRITICAL"
