"""
Mission Control - eine schlanke Steuerzentrale fuer einen lokalen llama-swap Stack.

Dieser Einstieg haelt nur noch das Geruest zusammen: er baut die FastAPI-App,
haengt die Router ein und liefert das statische UI aus. Die eigentliche Logik
liegt nach Concern getrennt in:
  - config.py      Env-Vars / Konstanten
  - auth.py        optionale Token-Auth
  - jobengine.py   Hintergrund-Jobs mit Live-Log
  - llamaswap.py   Reden mit llama-swap + config.yaml lesen/schreiben
  - routers/*      ein Router je Bereich (models, jobs, maintenance, ...)

Bewusst KISS: kein Build-Schritt, kein Framework ueber FastAPI hinaus, keine DB.
Neue Bereiche kommen als routers/<bereich>.py + static/js/panels/<bereich>.js dazu.
"""

from pathlib import Path

from fastapi import FastAPI, HTTPException
from fastapi.responses import FileResponse, JSONResponse, Response
from fastapi.staticfiles import StaticFiles

from routers import jobs, hermes, maintenance, memory, models, system, cookbook, integration, news

app = FastAPI(title="Mission Control")


@app.middleware("http")
async def _no_cache_static(request, call_next):
    """UI + statische Module immer revalidieren lassen (304 wenn unveraendert),
    damit Aenderungen nach einem rsync sofort wirken und kein Stale-JS haengen bleibt."""
    response = await call_next(request)
    path = request.url.path
    if path == "/" or path.startswith("/static"):
        response.headers["Cache-Control"] = "no-cache"
    return response


app.include_router(models.router)
app.include_router(jobs.router)
app.include_router(maintenance.router)
app.include_router(system.router)
app.include_router(cookbook.router)
app.include_router(integration.router)
app.include_router(news.router)
app.include_router(memory.router)
app.include_router(hermes.router)

_STATIC = Path(__file__).parent / "static"


@app.get("/")
def index():
    return FileResponse(_STATIC / "index.html")


_FAVICON = (
    b"<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 32 32'>"
    b"<rect width='32' height='32' rx='7' fill='#0f1720'/>"
    b"<circle cx='16' cy='16' r='8' fill='none' stroke='#2dd4bf' stroke-width='3'/>"
    b"<circle cx='16' cy='16' r='2.5' fill='#2dd4bf'/></svg>"
)


@app.get("/favicon.ico")
def favicon():
    return Response(content=_FAVICON, media_type="image/svg+xml")


app.mount("/static", StaticFiles(directory=_STATIC), name="static")


@app.exception_handler(HTTPException)
def _http_exc(_req, exc: HTTPException):
    return JSONResponse(status_code=exc.status_code, content={"error": exc.detail})


@app.exception_handler(Exception)
def _any_exc(_req, exc: Exception):
    """Unerwartete Fehler als lesbare Meldung ans (vertrauenswuerdige LAN-)UI geben,
    statt nur einen generischen 500 ohne Hinweis. Erleichtert Anfaengern die Diagnose."""
    return JSONResponse(status_code=500, content={"error": str(exc) or exc.__class__.__name__})
