import logging
from collections.abc import AsyncIterator
from contextlib import asynccontextmanager
from typing import Any

from fastapi import FastAPI, Request
from fastapi.responses import JSONResponse
from langgraph.checkpoint.sqlite import SqliteSaver

from vdash.config import Environment, Settings
from vdash.core import Database
from vdash.modules.llm import BaseLlm
from vdash.pipelines import sql
from vdash.utils import CryptoHelper

from .v1.api import api_router

logger = logging.getLogger(__name__)


def create_fastapi(settings: Settings, db: Database, llm: BaseLlm) -> FastAPI:
    @asynccontextmanager
    async def lifespan(app: FastAPI) -> AsyncIterator[None]:
        with SqliteSaver.from_conn_string(settings.checkpoint_db_path) as checkpointer:
            app.state.sql_agent = sql.SqlAgent(llm=llm, checkpointer=checkpointer)
            yield
            logger.info("Application shutting down, disconnecting database...")
            app.state.db.disconnect()

    app_kwargs: dict[str, Any] = {}
    if settings.environment == Environment.DEV:
        app_kwargs.update(
            {
                "debug": True,
            }
        )
    elif settings.environment == Environment.PROD:
        app_kwargs.update(
            {
                "docs_url": None,
                "redoc_url": None,
                "openapi_url": None,
            }
        )

    app = FastAPI(lifespan=lifespan, **app_kwargs)
    app.state.db = db
    app.state.llm = llm
    app.state.settings = settings
    app.state.crypto_helper = CryptoHelper(settings.secret_key)
    app.include_router(api_router, prefix="/api/v1")

    @app.exception_handler(Exception)
    async def global_exception_handler(request: Request, exc: Exception):
        logger.error(f"Unhandled exception: {exc}", exc_info=True)
        return JSONResponse(
            status_code=500,
            content={"message": "Internal Server Error"},
        )

    return app
