from contextlib import asynccontextmanager
from collections.abc import AsyncGenerator

from fastapi import FastAPI, Request
from fastapi.middleware.cors import CORSMiddleware
from fastapi.responses import JSONResponse
from prometheus_client import make_asgi_app

from src.core.exceptions import PIPException
from src.core.logging import configure_logging
from src.core.metrics import metrics_middleware
from src.core.tracing import setup_tracing
from src.infrastructure.cache.redis_cache import redis_cache
from src.infrastructure.config.settings import settings
from src.infrastructure.messaging.rabbitmq import rabbitmq_client
from src.api.middleware.audit import AuditMiddleware
from src.api.middleware.logging import RequestLoggingMiddleware
from src.api.middleware.rate_limit import RateLimitMiddleware
from src.api.v1.router import v1_router
from src.infrastructure.database.session import engine


@asynccontextmanager
async def lifespan(app: FastAPI) -> AsyncGenerator[None, None]:
    configure_logging()
    setup_tracing(app, engine=engine)

    await redis_cache.connect()
    await rabbitmq_client.connect()

    yield

    await rabbitmq_client.disconnect()
    await redis_cache.disconnect()
    await engine.dispose()


def create_app() -> FastAPI:
    application = FastAPI(
        title=settings.APP_NAME,
        version=settings.APP_VERSION,
        description="Pharmacy Integration Platform — unified API between pharmacy ERPs and external applications",
        docs_url="/docs",
        redoc_url="/redoc",
        openapi_url="/openapi.json",
        lifespan=lifespan,
    )

    application.add_middleware(
        CORSMiddleware,
        allow_origins=settings.CORS_ORIGINS,
        allow_credentials=settings.CORS_ALLOW_CREDENTIALS,
        allow_methods=["*"],
        allow_headers=["*"],
    )

    application.add_middleware(RateLimitMiddleware)
    application.add_middleware(AuditMiddleware)
    application.add_middleware(RequestLoggingMiddleware)
    application.middleware("http")(metrics_middleware)

    application.include_router(v1_router)

    metrics_app = make_asgi_app()
    application.mount("/metrics", metrics_app)

    @application.exception_handler(PIPException)
    async def pip_exception_handler(request: Request, exc: PIPException) -> JSONResponse:
        return JSONResponse(status_code=exc.status_code, content=exc.to_dict())

    @application.exception_handler(Exception)
    async def generic_exception_handler(request: Request, exc: Exception) -> JSONResponse:
        return JSONResponse(status_code=500, content={"error": {"code": "INTERNAL_ERROR", "message": "Internal server error"}})

    return application


app = create_app()
