from __future__ import annotations

from contextlib import asynccontextmanager
from pathlib import Path

from fastapi import FastAPI
from fastapi.middleware.cors import CORSMiddleware
from fastapi.responses import FileResponse, JSONResponse
from fastapi.staticfiles import StaticFiles

from card_store import CARD_TEMPLATES_DIR, NANOBOT_WORKSPACE
from routes import (
    cards_router,
    inbox_router,
    messages_router,
    rtc_router,
    sessions_router,
    templates_router,
    tools_router,
    workbench_router,
)
from session_store import list_web_sessions, normalize_session_chat_id
from web_runtime import create_web_runtime

BASE_DIR = Path(__file__).resolve().parent
DIST_DIR = BASE_DIR / "frontend" / "dist"
NANOBOT_REPO_DIR = BASE_DIR.parent / "nanobot"
NANOBOT_RUNTIME_WORKSPACE = (
    (NANOBOT_WORKSPACE / "workspace")
    if (NANOBOT_WORKSPACE / "workspace").exists()
    else NANOBOT_WORKSPACE
)
INBOX_DIR = NANOBOT_RUNTIME_WORKSPACE / "inbox"
TOOL_JOB_TIMEOUT_SECONDS = 300.0
TOOL_JOB_RETENTION_SECONDS = 15 * 60


@asynccontextmanager
async def app_lifespan(app: FastAPI):
    runtime = create_web_runtime(
        repo_dir=NANOBOT_REPO_DIR,
        inbox_dir=INBOX_DIR,
        tool_job_timeout_seconds=TOOL_JOB_TIMEOUT_SECONDS,
        tool_job_retention_seconds=TOOL_JOB_RETENTION_SECONDS,
        list_sessions=list_web_sessions,
        normalize_chat_id=normalize_session_chat_id,
    )
    app.state.runtime = runtime
    try:
        yield
    finally:
        await runtime.shutdown()


def create_app() -> FastAPI:
    app = FastAPI(title="Nanobot SuperTonic Wisper Web", lifespan=app_lifespan)

    app.add_middleware(
        CORSMiddleware,
        allow_origins=["*"],
        allow_methods=["*"],
        allow_headers=["*"],
    )

    @app.get("/health")
    async def health() -> JSONResponse:
        return JSONResponse({"status": "ok"})

    app.include_router(tools_router)
    app.include_router(sessions_router)
    app.include_router(cards_router)
    app.include_router(workbench_router)
    app.include_router(inbox_router)
    app.include_router(templates_router)
    app.include_router(messages_router)
    app.include_router(rtc_router)

    if DIST_DIR.exists():
        assets_dir = DIST_DIR / "assets"
        if assets_dir.exists():
            app.mount("/assets", StaticFiles(directory=str(assets_dir)), name="assets")
        if CARD_TEMPLATES_DIR.exists():
            app.mount(
                "/card-templates",
                StaticFiles(directory=str(CARD_TEMPLATES_DIR)),
                name="card-templates",
            )

        @app.get("/{full_path:path}")
        async def spa_fallback(full_path: str) -> FileResponse:
            candidate = DIST_DIR / full_path
            if candidate.is_file():
                return FileResponse(str(candidate))
            response = FileResponse(str(DIST_DIR / "index.html"))
            response.headers["Cache-Control"] = "no-store, no-cache, must-revalidate"
            response.headers["Pragma"] = "no-cache"
            response.headers["Expires"] = "0"
            return response

    return app


app = create_app()
