"""FastAPI composition root: wiring, lifespan, middleware, routers."""

from collections.abc import AsyncIterator
from contextlib import asynccontextmanager

from fastapi import FastAPI, WebSocket

from app.api.errors import register_exception_handlers
from app.api.health import router as health_router
from app.api.middleware import CorrelationIdMiddleware
from app.api.rest import subsonic_router
from app.api.v1 import api_v1_router
from app.core.config import app_version, get_settings
from app.core.logging import configure_logging, get_logger
from app.infrastructure.cache import close_redis
from app.infrastructure.db import dispose_engine

log = get_logger(__name__)


@asynccontextmanager
async def lifespan(_app: FastAPI) -> AsyncIterator[None]:
    settings = get_settings()
    log.info("startup", environment=settings.environment)
    yield
    log.info("shutdown")
    await dispose_engine()
    await close_redis()


def create_app() -> FastAPI:
    settings = get_settings()
    configure_logging(level=settings.log_level, json=settings.log_json)

    app = FastAPI(
        title="mcma-backend",
        version=app_version(),
        summary="Self-hosted, offline-first music service.",
        lifespan=lifespan,
    )

    app.add_middleware(CorrelationIdMiddleware)
    register_exception_handlers(app)

    app.include_router(health_router)
    app.include_router(api_v1_router)
    app.include_router(subsonic_router, prefix="/rest")

    @app.websocket("/ws")
    async def ws_stub(websocket: WebSocket) -> None:
        await websocket.accept()
        await websocket.close(1001)

    return app


app = create_app()
