"""Meta Ads MCP Server using FastMCP.

Migrated to FastMCP for:
- Decorator-based tool registration
- Lifespan management for MetaClient
- Context injection for logging
- Structured output support

MCP SDK v1.x Enhancements:
- MCP Resources for data access
- MCP Prompts for workflow guidance
"""
from __future__ import annotations

import os
from contextlib import asynccontextmanager
from collections.abc import AsyncIterator
from dataclasses import dataclass
from typing import TYPE_CHECKING

from dotenv import load_dotenv
from mcp.server.fastmcp import FastMCP

from .config import initialize_settings
from .logging import configure_logging, get_logger
from .meta_client import MetaClient, build_client_from_env
from .tools import register_all_tools

if TYPE_CHECKING:
    pass

logger = get_logger(__name__)


def _build_token_verifier(settings):
    """Create hosted-mode token verifier when auth settings are configured."""
    if not settings.hosted_mode:
        return None

    from .auth import HostedJWTTokenVerifier, JWTValidator

    validator = JWTValidator(
        public_key=settings.jwt_public_key,
        issuer=settings.jwt_issuer,
        audience=settings.jwt_audience,
        algorithm=settings.jwt_algorithm,
    )
    return HostedJWTTokenVerifier(validator)


@dataclass
class AppContext:
    """Application context holding shared resources."""
    client: MetaClient


@asynccontextmanager
async def app_lifespan(server: FastMCP) -> AsyncIterator[AppContext]:
    """Lifespan manager for MetaClient initialization and cleanup."""
    load_dotenv()
    configure_logging(os.getenv("LOG_LEVEL"))
    settings = initialize_settings(validate=True)
    
    logger.info(f"server_starting: {server.name}")

    # Keep FastMCP runtime settings aligned with project configuration.
    server.settings.host = settings.http_host
    server.settings.port = settings.http_port
    server.settings.log_level = settings.log_level.upper()
    
    # Startup: initialize MetaClient
    client = await build_client_from_env(settings)
    
    # Set global client for backward compatibility
    from .meta_client import set_client
    set_client(client)

    # Configure circuit breaker from settings.
    if settings.circuit_breaker_enabled:
        from .circuit_breaker import configure_circuit_breaker
        configure_circuit_breaker(
            failure_threshold=settings.circuit_breaker_failure_threshold,
            recovery_timeout=settings.circuit_breaker_timeout,
        )

    # Bootstrap observability once at startup.
    from .observability import setup_observability
    setup_observability(
        service_name=settings.server_name,
        service_version="1.0.0",
        enable_prometheus=True,
        enable_tracing=bool(settings.otel_exporter_otlp_endpoint),
        enable_metrics=bool(settings.otel_exporter_otlp_endpoint),
        otlp_endpoint=settings.otel_exporter_otlp_endpoint,
    )
    
    try:
        yield AppContext(client=client)
    finally:
        # Shutdown: cleanup
        logger.info("server_shutting_down")
        await client.aclose()
        if client.enable_caching:
            from .cache import close_cache
            await close_cache()
        from .secrets_provider import close_secrets_provider
        await close_secrets_provider()


# Create FastMCP server with lifespan
load_dotenv()
_bootstrap_settings = initialize_settings(validate=False)
mcp = FastMCP(
    "meta-ads-mcp",
    lifespan=app_lifespan,
    token_verifier=_build_token_verifier(_bootstrap_settings),
)


# Import and register all tools
register_all_tools(mcp)

# Register MCP Resources (MCP SDK v1.x)
try:
    from .resources import register_resources
    register_resources(mcp)
    logger.info("MCP resources registered successfully")
except ImportError as e:
    logger.warning(f"Could not register MCP resources: {e}")

# Register MCP Prompts (MCP SDK v1.x)
try:
    from .prompts import register_prompts
    register_prompts(mcp)
    logger.info("MCP prompts registered successfully")
except ImportError as e:
    logger.warning(f"Could not register MCP prompts: {e}")


def main() -> None:
    """Main entry point with configurable transport."""
    load_dotenv()
    settings = initialize_settings(validate=True)
    transport_map = {
        "stdio": "stdio",
        "http": "streamable-http",
        "websocket": "sse",
    }
    transport = transport_map.get(settings.transport_type)
    if not transport:
        raise ValueError(f"Unsupported transport_type: {settings.transport_type}")
    logger.info(
        "server_transport_selected configured=%s mcp_transport=%s",
        settings.transport_type,
        transport,
    )
    mcp.run(transport=transport)


if __name__ == "__main__":
    main()
