import logging
from contextlib import asynccontextmanager

from fastapi import FastAPI
from fastapi.middleware.cors import CORSMiddleware
from fastapi.middleware.gzip import GZipMiddleware

from app.config import settings
from app.router import root_api_router
from app.exceptions import (
    HTTPException,
    http_exception_handler,
    GlobalExceptionMiddleware
)

log = logging.getLogger(__name__)


@asynccontextmanager
async def lifespan(app: FastAPI):
    """
    Define FastAPI lifespan events (startup and shutdown).
    Handles database connection pool and other cleanup tasks.
    """
    # Startup
    log.info("Execute FastAPI startup event handler.")
    
    yield
  
    # Shutdown
    log.warning("Execute FastAPI shutdown event handler.")
    

def get_application() -> FastAPI:
    """
    Initialize FastAPI application.
    """
    log.debug("Initialize FastAPI application node.")
    
    app = FastAPI(
        title=settings.PROJECT_NAME,
        debug=settings.DEBUG,
        servers=[{'url': 'http://127.0.0.1:9000'}],
        docs_url=settings.DOCS_URL if settings.ENV == "development" else None,
        redoc_url=settings.REDOC_URL if settings.ENV == "development" else None,
        openapi_url=settings.OPENAPI_URL if settings.ENV == "development" else None,
        lifespan=lifespan
    )
    
    # Add Global Exception Middleware as the outermost layer
    app.add_middleware(GlobalExceptionMiddleware)
    app.add_middleware(GZipMiddleware, minimum_size=1000)

    # Add CORS middleware
    app.add_middleware(
        CORSMiddleware,
        allow_origins=["*"],
        allow_credentials=True,
        allow_methods=["GET", "POST", "PUT", "DELETE", "OPTIONS", "PATCH"],
        allow_headers=["*"]
    )

    # Add routes
    log.debug("Add application routes.")
    app.include_router(root_api_router)
    
    # Add exception handlers
    log.debug("Register global exception handler for custom HTTPException.")
    app.add_exception_handler(HTTPException, http_exception_handler)
    
    return app

__all__ = ("get_application",)