"""FastAPI application factory for the DataBridge Graph API Gateway.

Creates a FastAPI app that exposes all MCP tools over REST, MCP-over-HTTP,
WebSocket, and SSE — unified under a single domain.
"""

from __future__ import annotations

import logging
from contextlib import asynccontextmanager
from typing import Any

from fastapi import FastAPI
from fastapi.middleware.cors import CORSMiddleware
from fastapi.responses import JSONResponse

from .registry import ToolRegistry

logger = logging.getLogger(__name__)


def create_app(
    dynamic_registry: Any,
    tenant_registry: Any = None,
) -> FastAPI:
    """Build the gateway FastAPI application.

    Args:
        dynamic_registry: DynamicToolRegistry instance (from src/plugins/dynamic_registry.py).
        tenant_registry: Optional TenantRegistry for multi-tenant support.

    Returns:
        Configured FastAPI application with all adapters mounted.
    """
    registry = ToolRegistry(dynamic_registry, tenant_registry)

    @asynccontextmanager
    async def lifespan(app: FastAPI):
        logger.info(
            "DataBridge Graph API starting — %d tools across %d domains",
            dynamic_registry.total_count,
            len(dynamic_registry.get_all_domains()),
        )
        yield
        logger.info("DataBridge Graph API shutting down")

    app = FastAPI(
        title="DataBridge Graph API",
        description="Unified API gateway for DataBridge MCP tools",
        version="0.43.0",
        docs_url="/docs",
        redoc_url="/redoc",
        lifespan=lifespan,
    )

    # CORS
    app.add_middleware(
        CORSMiddleware,
        allow_origins=["*"],
        allow_credentials=True,
        allow_methods=["*"],
        allow_headers=["*"],
    )

    # Stash registry on app state for adapters
    app.state.registry = registry
    app.state.tenant_registry = tenant_registry

    # ------------------------------------------------------------------
    # Mount adapters
    # ------------------------------------------------------------------

    # Phase 1: REST adapter
    from .adapters.rest import router as rest_router, init_rest
    init_rest(registry, tenant_registry)
    app.include_router(rest_router)

    # Phase 2: MCP-over-HTTP adapter
    from .adapters.mcp_http import router as mcp_router, init_mcp
    init_mcp(registry, tenant_registry)
    app.include_router(mcp_router)

    # Phase 3: WebSocket adapter
    from .adapters.websocket import router as ws_router, init_ws
    init_ws(registry, tenant_registry)
    app.include_router(ws_router)

    # Phase 4: SSE adapter
    from .adapters.sse import router as sse_router, init_sse
    init_sse(registry, tenant_registry)
    app.include_router(sse_router)

    # Phase 6: Tier gating + rate limiting
    try:
        from .middleware.tier_gate import TierGate
        from .middleware.rate_limiter import RateLimiter

        registry._tier_gate = TierGate()
        registry._rate_limiter = RateLimiter()
        logger.info("Tier gating and rate limiting enabled")
    except Exception as exc:
        logger.warning("Tier/rate middleware not loaded: %s", exc)

    # Phase 5: Custom OpenAPI schema from tool metadata
    _apply_custom_openapi(app, registry)

    # ------------------------------------------------------------------
    # Health / info endpoints
    # ------------------------------------------------------------------

    @app.get("/health", tags=["System"])
    async def health():
        return {"status": "ok", "tools": dynamic_registry.total_count}

    @app.get("/info", tags=["System"])
    async def info():
        return {
            "name": "DataBridge Graph API",
            "version": "0.43.0",
            "tools": dynamic_registry.total_count,
            "domains": len(dynamic_registry.get_all_domains()),
            "mode": dynamic_registry.mode,
            "protocols": ["rest", "mcp", "ws", "sse"],
        }

    return app


def _apply_custom_openapi(app: FastAPI, registry: ToolRegistry) -> None:
    """Replace the default OpenAPI schema with one generated from tool metadata."""

    def custom_openapi():
        if app.openapi_schema:
            return app.openapi_schema
        schema = registry.generate_openapi_paths()
        app.openapi_schema = schema
        return schema

    app.openapi = custom_openapi
