from contextlib import asynccontextmanager
from pathlib import Path

from fastapi import FastAPI
from fastapi.responses import FileResponse
from fastapi.staticfiles import StaticFiles

from app.api import api_router
from app.core.config import load_dotenv_file
from app.core.database import init_database
from app.core.middleware import (
    ApiVersionAliasMiddleware,
    PasswordChangeGateMiddleware,
    RequestContextMiddleware,
)
from app.services.chat_runtime import chat_runtime
from app.version import __version__

load_dotenv_file()

BASE_DIR = Path(__file__).resolve().parent.parent
DIST_DIR = BASE_DIR / "dist"


@asynccontextmanager
async def lifespan(_app: FastAPI):
    init_database()
    await chat_runtime.start()
    try:
        yield
    finally:
        await chat_runtime.stop()


def create_app() -> FastAPI:
    app = FastAPI(title="ComPilot Scan", version=__version__, lifespan=lifespan)
    app.add_middleware(PasswordChangeGateMiddleware)
    app.add_middleware(RequestContextMiddleware)
    app.add_middleware(ApiVersionAliasMiddleware)
    app.include_router(api_router)

    if (DIST_DIR / "assets").is_dir():
        app.mount("/assets", StaticFiles(directory=DIST_DIR / "assets"), name="assets")

    @app.get("/")
    async def serve_index():
        index = DIST_DIR / "index.html"
        if index.is_file():
            return FileResponse(index)
        return {
            "message": "ComPilot Scan API",
            "docs": "/docs",
            "hint": "cd web && npm run build",
        }

    @app.get("/{path:path}")
    async def spa_fallback(path: str):
        if path.startswith("api") or path in ("docs", "openapi.json", "redoc"):
            return {"detail": "Not Found"}
        file_path = (DIST_DIR / path).resolve()
        if file_path.is_file() and DIST_DIR in file_path.parents:
            return FileResponse(file_path)
        index = DIST_DIR / "index.html"
        if index.is_file():
            return FileResponse(index)
        return {"detail": "Not Found"}

    return app


app = create_app()