from contextlib import AsyncExitStack, asynccontextmanager
from pathlib import Path

from fastapi import FastAPI
from zodiac_core.cache import cache
from zodiac_core.config import ConfigManagement
from zodiac_core.db import db
from zodiac_core.exception_handlers import register_exception_handlers
from zodiac_core.logging import setup_loguru
from zodiac_core.middleware import register_middleware

from app.core.config import CacheConfig, DbConfig
from app.core.container import Container


@asynccontextmanager
async def lifespan(app: FastAPI):
    async with AsyncExitStack() as stack:
        container = app.state.container
        await container.init_resources()
        stack.push_async_callback(container.shutdown_resources)

        db_cfg = ConfigManagement.provide_config(container.config.db(), DbConfig)
        db.setup(database_url=db_cfg.url, echo=db_cfg.echo)
        stack.push_async_callback(db.shutdown)

        cache_cfg = ConfigManagement.provide_config(container.config.cache(), CacheConfig)
        cache.setup(prefix=cache_cfg.prefix, default_ttl=cache_cfg.default_ttl)
        stack.push_async_callback(cache.shutdown)

        await db.create_all()
        yield


def create_app() -> FastAPI:
    setup_loguru(
        level="INFO",
        json_format=True,
        service_name="{{ project_name }}",
    )

    config_dir = Path(__file__).resolve().parent / "config"
    container = Container.initialize([config_dir])

    app = FastAPI(title="{{ project_name }}", lifespan=lifespan)
    app.state.container = container

    register_middleware(app)
    register_exception_handlers(app)

    from app.api.router import api_router

    app.include_router(api_router)

    return app


app = create_app()
