from contextlib import asynccontextmanager
from collections.abc import AsyncIterator

from fastapi import Depends, FastAPI
from sqlalchemy import text
from starlette.middleware.trustedhost import TrustedHostMiddleware

from app.auth.router import router as auth_router
from app.config import get_settings
from app.customers.router import router as customer_router
from app.db import create_database
from app.observability import configure_logging, register_observability
from app.perusahaan.router import router as company_router
from app.sales.order_router import router as sales_order_router
from app.sales.router import router as sales_router
from app.security import get_current_principal


@asynccontextmanager
async def lifespan(app: FastAPI) -> AsyncIterator[None]:
    engine, session_factory = create_database(get_settings())
    app.state.db_session_factory = session_factory
    try:
        yield
    finally:
        await engine.dispose()


def create_app() -> FastAPI:
    settings = get_settings()
    settings.validate_runtime()
    configure_logging(settings.log_level)
    app = FastAPI(
        title=settings.app_name,
        version="0.1.0",
        lifespan=lifespan,
    )
    app.add_middleware(
        TrustedHostMiddleware, allowed_hosts=settings.trusted_host_list
    )
    register_observability(app)
    app.include_router(auth_router)
    auth_dependencies = [Depends(get_current_principal)]
    app.include_router(sales_router, dependencies=auth_dependencies)
    app.include_router(sales_order_router, dependencies=auth_dependencies)
    app.include_router(customer_router, dependencies=auth_dependencies)
    app.include_router(company_router, dependencies=auth_dependencies)

    @app.get("/health", tags=["system"])
    async def health() -> dict[str, str]:
        return {"status": "ok"}

    @app.get("/health/ready", tags=["system"])
    async def readiness() -> dict[str, str]:
        async with app.state.db_session_factory() as session:
            await session.execute(text("SELECT 1"))
        return {"status": "ready"}

    return app


app = create_app()