"""``setup_lifespan`` — wire :func:`mgf.common.bootstrap` into FastAPI.

Returns an async context manager FastAPI accepts as its
``lifespan=`` argument. Inside the lifespan, :func:`bootstrap` runs;
the resulting :class:`AppContext` is stashed on ``app.state.mgf_context``
so dependencies can read it.

When the app shuts down (signal, ASGI shutdown, etc.), the
:class:`AppContext` LIFO-unwinds — exactly like a synchronous
``with bootstrap(...):`` block would.
"""

from __future__ import annotations

from contextlib import AbstractAsyncContextManager, asynccontextmanager
from typing import TYPE_CHECKING

from mgf.common import bootstrap

if TYPE_CHECKING:
    from collections.abc import Callable

    from mgf.common.settings import MgfSettings

    from fastapi import FastAPI


def setup_lifespan(
    *,
    app_name: str | None = None,
    app_version: str | None = None,
    settings: MgfSettings | None = None,
) -> Callable[[FastAPI], AbstractAsyncContextManager[None]]:
    """Build a FastAPI lifespan that runs :func:`mgf.common.bootstrap`.

    Use as::

        from fastapi import FastAPI
        from mgf.fastapi import setup_lifespan

        app = FastAPI(
            lifespan=setup_lifespan(
                app_name="myapp",
                app_version="1.0.0",
            )
        )

    With ``app_name`` / ``app_version`` omitted, the same auto-derivation
    rules apply as with bare :func:`bootstrap` (see
    ``docs/reference/lifecycle.md``). The resulting :class:`AppContext`
    is stashed on ``app.state.mgf_context`` for dependency injection
    via :func:`mgf.fastapi.get_app_context`.

    The lifespan is an async context manager; on app shutdown the
    :class:`AppContext` LIFO-unwinds (logging handlers detach, OTel
    flushes, crash-reporter excepthook restores, etc.).
    """

    @asynccontextmanager
    async def _lifespan(app: FastAPI):  # type: ignore[no-untyped-def]
        with bootstrap(
            app_name=app_name,
            app_version=app_version,
            settings=settings,
        ) as ctx:
            app.state.mgf_context = ctx
            yield

    return _lifespan


__all__ = ["setup_lifespan"]
