"""FastAPI application — Sanad Dashboard.

Each route module is imported INDIVIDUALLY inside try/except so that one
broken router (missing dep, syntax error in a sibling) cannot break the
entire dashboard. Failed routers are logged and the server starts without
them.
"""

from __future__ import annotations

import importlib
import logging

# Backfill asyncio.to_thread on Python 3.8 — must run before any router import.
from Project.Sanad.core import asyncio_compat  # noqa: F401

from fastapi import FastAPI
from fastapi.staticfiles import StaticFiles

from Project.Sanad.config import BASE_DIR
from Project.Sanad.core.logger import get_logger

log = get_logger("dashboard.app")

from Project.Sanad.core.config_loader import section as _cfg_section
_APP_CFG = _cfg_section("dashboard", "app")
app = FastAPI(
    title=_APP_CFG.get("title", "Sanad Dashboard"),
    version=_APP_CFG.get("version", "1.0.0"),
)


# -- isolated route registration --

_REST_ROUTES: list[tuple[str, str, str]] = [
    # (module_name, prefix, tag)
    ("health",          "/api",                 "health"),
    ("system",          "/api/system",          "system"),
    ("voice",           "/api/voice",           "voice"),
    ("motion",          "/api/motion",          "motion"),
    ("skills",          "/api/skills",          "skills"),
    ("macros",          "/api/macros",          "macros"),
    ("logs",            "/api/logs",            "logs"),
    ("replay",          "/api/replay",          "replay"),
    ("audio_control",   "/api/audio",           "audio"),
    ("scripts",         "/api/scripts",         "scripts"),
    ("records",         "/api/records",         "records"),
    ("prompt",          "/api/prompt",          "prompt"),
    ("wake_phrases",    "/api/wake-phrases",    "wake-phrases"),
    ("live_voice",      "/api/live-voice",      "live-voice"),
    ("live_subprocess", "/api/live-subprocess", "live-subprocess"),
    ("typed_replay",    "/api/typed-replay",    "typed-replay"),
]

_WS_ROUTES: list[str] = ["log_stream"]

_loaded_routes: list[str] = []
_failed_routes: dict[str, str] = {}


def _register_router(module_name: str, prefix: str | None = None, tag: str | None = None,
                     package: str = "Project.Sanad.dashboard.routes"):
    """Import + register one router. Failures are logged, never raised."""
    full_name = f"{package}.{module_name}"
    try:
        mod = importlib.import_module(full_name)
        if not hasattr(mod, "router"):
            raise AttributeError(f"{full_name} has no 'router' attribute")
        kwargs: dict = {}
        if prefix is not None:
            kwargs["prefix"] = prefix
        if tag is not None:
            kwargs["tags"] = [tag]
        app.include_router(mod.router, **kwargs)
        _loaded_routes.append(module_name)
        log.info("Registered router: %s", module_name)
    except Exception as exc:
        _failed_routes[module_name] = str(exc)
        log.exception("Failed to register router %s — skipping", module_name)


# REST routes
for mod_name, prefix, tag in _REST_ROUTES:
    _register_router(mod_name, prefix=prefix, tag=tag)

# WebSocket routes
for mod_name in _WS_ROUTES:
    _register_router(
        mod_name,
        package="Project.Sanad.dashboard.websockets",
        tag="websocket",
    )


# -- Static files (dashboard UI) — best effort --
STATIC_DIR = BASE_DIR / _APP_CFG.get("static_subdir", "dashboard/static")
try:
    STATIC_DIR.mkdir(parents=True, exist_ok=True)
    app.mount("/static", StaticFiles(directory=str(STATIC_DIR)), name="static")
    log.info("Static dir mounted: %s", STATIC_DIR)
except Exception:
    log.exception("Could not mount static dir %s — serving without it", STATIC_DIR)


@app.get("/")
async def root():
    """Serve the dashboard SPA."""
    index = STATIC_DIR / "index.html"
    if index.exists():
        from fastapi.responses import HTMLResponse
        try:
            return HTMLResponse(index.read_text(encoding="utf-8"))
        except OSError as exc:
            return {"error": f"Could not read index.html: {exc}"}
    return {
        "message": "Sanad Dashboard — index.html not found",
        "loaded_routes": _loaded_routes,
        "failed_routes": _failed_routes,
    }


@app.get("/api/_dashboard_status")
async def dashboard_load_status():
    """Diagnostic — which routers loaded, which failed."""
    return {
        "loaded": _loaded_routes,
        "failed": _failed_routes,
        "total_loaded": len(_loaded_routes),
        "total_failed": len(_failed_routes),
    }
