"""
Entrypoint FastAPI – registra router, middleware, startup/shutdown.
"""

from contextlib import asynccontextmanager
from typing import AsyncGenerator

from fastapi import FastAPI, Request, status
from fastapi.middleware.cors import CORSMiddleware
from fastapi.responses import JSONResponse
from slowapi import Limiter, _rate_limit_exceeded_handler
from slowapi.errors import RateLimitExceeded
from slowapi.middleware import SlowAPIMiddleware
from slowapi.util import get_remote_address

from app.api.v1 import auth, mailboxes, permissions, send, tenants, users, ws
from app.config import get_settings
from app.core.logging import get_logger, setup_logging
from app.database import engine
from app.websocket.manager import redis_subscriber_loop

settings = get_settings()
logger = get_logger(__name__)


@asynccontextmanager
async def lifespan(app: FastAPI) -> AsyncGenerator[None, None]:
    """Gestione ciclo di vita dell'applicazione."""
    import asyncio

    setup_logging()
    logger.info(
        "🚀 PecFlow Backend avviato",
        extra={"env": settings.app_env, "debug": settings.app_debug},
    )

    # Avvia il subscriber Redis per il forward degli eventi WebSocket
    redis_task = asyncio.create_task(
        redis_subscriber_loop(settings.redis_url),
        name="redis-ws-subscriber",
    )

    yield

    # Cleanup
    redis_task.cancel()
    try:
        await redis_task
    except asyncio.CancelledError:
        pass
    # Chiudi pool arq se aperto
    from app.services.send_service import close_arq_pool
    await close_arq_pool()
    await engine.dispose()
    logger.info("🛑 PecFlow Backend fermato")


# ─── Applicazione FastAPI ─────────────────────────────────────────────────────
limiter = Limiter(key_func=get_remote_address, default_limits=["200/minute"])

app = FastAPI(
    title="PecFlow API",
    description="API per la gestione PEC SaaS multi-tenant",
    version="1.0.0",
    docs_url="/docs" if not settings.is_production else None,
    redoc_url="/redoc" if not settings.is_production else None,
    lifespan=lifespan,
)

# ─── Middleware ───────────────────────────────────────────────────────────────
app.state.limiter = limiter
app.add_exception_handler(RateLimitExceeded, _rate_limit_exceeded_handler)
app.add_middleware(SlowAPIMiddleware)

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

# ─── Router ───────────────────────────────────────────────────────────────────
API_PREFIX = "/api/v1"

app.include_router(auth.router, prefix=API_PREFIX)
app.include_router(users.router, prefix=API_PREFIX)
app.include_router(tenants.router, prefix=API_PREFIX)
app.include_router(permissions.router, prefix=API_PREFIX)
app.include_router(mailboxes.router, prefix=API_PREFIX)
app.include_router(send.router, prefix=API_PREFIX)
app.include_router(ws.router, prefix=API_PREFIX)


# ─── Health check ─────────────────────────────────────────────────────────────
@app.get("/health", tags=["Health"], include_in_schema=False)
async def health_check() -> dict:
    """Endpoint di health check per Docker/Kubernetes."""
    return {
        "status": "ok",
        "version": "1.0.0",
        "env": settings.app_env,
    }


@app.get("/health/db", tags=["Health"], include_in_schema=False)
async def health_db() -> dict:
    """Verifica connessione al database."""
    from sqlalchemy import text
    from app.database import AsyncSessionLocal

    try:
        async with AsyncSessionLocal() as session:
            await session.execute(text("SELECT 1"))
        return {"status": "ok", "database": "connected"}
    except Exception as e:
        return JSONResponse(
            status_code=status.HTTP_503_SERVICE_UNAVAILABLE,
            content={"status": "error", "database": str(e)},
        )


# ─── Error handler globale ────────────────────────────────────────────────────
@app.exception_handler(Exception)
async def global_exception_handler(request: Request, exc: Exception) -> JSONResponse:
    logger.exception(f"Errore non gestito: {exc}")
    return JSONResponse(
        status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
        content={"detail": "Errore interno del server"},
    )
