"""
Transport Abstraction.

Wraps FastMCP transport mechanisms (stdio, HTTP, SSE) with strategy pattern.
"""

from enum import Enum
from typing import Any

from fastmcp import FastMCP


class TransportType(str, Enum):
    """Supported transport types."""

    STDIO = "stdio"
    HTTP = "http"
    SSE = "sse"


class TransportStrategy:
    """
    Strategy for selecting and configuring transport.

    Uses Strategy + Adapter pattern to select transport based on config.
    """

    def __init__(self, transport: str = "stdio", host: str = "0.0.0.0", port: int = 8000):
        """
        Initialize transport strategy.

        Args:
            transport: Transport type (default: "stdio")
            host: HTTP host (default: "0.0.0.0")
            port: HTTP port (default: 8000)
        """
        self.transport = transport
        self.host = host
        self.port = port

    def run(self, mcp: FastMCP, **kwargs: Any) -> None:
        """
        Run server with configured transport.

        Args:
            mcp: FastMCP server instance
            **kwargs: Additional transport parameters
        """
        transport = kwargs.get("transport") or self.transport
        if isinstance(transport, str):
            transport = TransportType(transport.lower())

        if transport == TransportType.STDIO:
            self._run_stdio(mcp)
        elif transport == TransportType.HTTP:
            self._run_http(mcp, **kwargs)
        elif transport == TransportType.SSE:
            self._run_sse(mcp, **kwargs)
        else:
            raise ValueError(f"Unsupported transport: {transport}")

    async def run_async(self, mcp: FastMCP, **kwargs: Any) -> None:
        """
        Run server asynchronously with configured transport.

        Args:
            mcp: FastMCP server instance
            **kwargs: Additional transport parameters
        """
        transport = kwargs.get("transport") or self.transport
        if isinstance(transport, str):
            transport = TransportType(transport.lower())

        if transport == TransportType.STDIO:
            await self._run_stdio_async(mcp)
        elif transport == TransportType.HTTP:
            await self._run_http_async(mcp, **kwargs)
        elif transport == TransportType.SSE:
            await self._run_sse_async(mcp, **kwargs)
        else:
            raise ValueError(f"Unsupported transport: {transport}")

    def _run_stdio(self, mcp: FastMCP) -> None:
        """Run with stdio transport."""
        mcp.run()

    async def _run_stdio_async(self, mcp: FastMCP) -> None:
        """Run with stdio transport (async)."""
        # FastMCP may support async stdio
        if hasattr(mcp, "run_async"):
            await mcp.run_async()
        else:
            # Fallback to sync
            mcp.run()

    def _run_http(self, mcp: FastMCP, **kwargs: Any) -> None:
        """Run with HTTP transport."""
        host = kwargs.get("host") or self.host
        port = kwargs.get("port") or self.port

        if hasattr(mcp, "run"):
            # FastMCP HTTP transport
            mcp.run(transport="http", host=host, port=port)
        else:
            raise NotImplementedError("HTTP transport not available")

    async def _run_http_async(self, mcp: FastMCP, **kwargs: Any) -> None:
        """Run with HTTP transport (async)."""
        host = kwargs.get("host") or self.host
        port = kwargs.get("port") or self.port

        if hasattr(mcp, "run_async"):
            await mcp.run_async(transport="http", host=host, port=port)
        else:
            # Fallback to sync
            self._run_http(mcp, host=host, port=port)

    def _run_sse(self, mcp: FastMCP, **kwargs: Any) -> None:
        """Run with SSE transport."""
        host = kwargs.get("host") or self.host
        port = kwargs.get("port") or self.port

        if hasattr(mcp, "run"):
            mcp.run(transport="sse", host=host, port=port)
        else:
            raise NotImplementedError("SSE transport not available")

    async def _run_sse_async(self, mcp: FastMCP, **kwargs: Any) -> None:
        """Run with SSE transport (async)."""
        host = kwargs.get("host") or self.host
        port = kwargs.get("port") or self.port

        if hasattr(mcp, "run_async"):
            await mcp.run_async(transport="sse", host=host, port=port)
        else:
            # Fallback to sync
            self._run_sse(mcp, host=host, port=port)

    def get_asgi_app(self, mcp: FastMCP) -> Any:
        """
        Get ASGI application for HTTP transport.

        Args:
            mcp: FastMCP server instance

        Returns:
            ASGI application
        """
        if hasattr(mcp, "http_app"):
            return mcp.http_app()
        else:
            raise NotImplementedError("ASGI app not available")


def run_server(
    mcp: FastMCP, transport: str = "stdio", host: str = "0.0.0.0", port: int = 8000, **kwargs: Any
) -> None:
    """
    Run server with transport abstraction.

    Args:
        mcp: FastMCP server instance
        transport: Transport type (default: "stdio")
        host: HTTP host (default: "0.0.0.0")
        port: HTTP port (default: 8000)
        **kwargs: Additional transport parameters
    """
    strategy = TransportStrategy(transport=transport, host=host, port=port)
    strategy.run(mcp, **kwargs)


async def run_server_async(
    mcp: FastMCP, transport: str = "stdio", host: str = "0.0.0.0", port: int = 8000, **kwargs: Any
) -> None:
    """
    Run server asynchronously with transport abstraction.

    Args:
        mcp: FastMCP server instance
        transport: Transport type (default: "stdio")
        host: HTTP host (default: "0.0.0.0")
        port: HTTP port (default: 8000)
        **kwargs: Additional transport parameters
    """
    strategy = TransportStrategy(transport=transport, host=host, port=port)
    await strategy.run_async(mcp, **kwargs)
