"""FastAPI REST-API für appRobotBodyTrack."""
from __future__ import annotations

import json
import tempfile
from pathlib import Path
from typing import List, Optional

from fastapi import FastAPI, File, HTTPException, UploadFile
from fastapi.responses import JSONResponse

from scripts import __version__, estimate_from_dir

_robot_json: Optional[Path] = None


def create_app(robot_json: str | Path | None = None) -> FastAPI:
    """App-Fabrik — setzt optionale Server-weite robot.json-Konfig."""
    global _robot_json
    if robot_json:
        _robot_json = Path(robot_json).resolve()
        # Frühe, klare Warnung statt kryptischem 500 zur Laufzeit.
        # Häufige Falle: Docker legt für einen fehlenden Bind-Mount-Pfad
        # ein leeres VERZEICHNIS an — dann ist _robot_json zwar vorhanden,
        # aber keine Datei.
        if not _robot_json.is_file():
            import warnings
            grund = "ist ein Verzeichnis" if _robot_json.is_dir() else "existiert nicht"
            warnings.warn(
                f"robot.json {grund}: {_robot_json}. "
                f"/v1/config liefert 404, /v1/estimate verlangt einen robot_json-Upload. "
                f"Bei Docker: liegt die Datei wirklich am gemounteten Host-Pfad?",
                RuntimeWarning,
                stacklevel=2,
            )
    return _app


_app = FastAPI(title="approbot-pipeline", version=__version__)


@_app.get("/v1/health")
def health():
    return {"status": "ok", "version": __version__}


@_app.get("/v1/config")
def config():
    if _robot_json is None or not _robot_json.is_file():
        raise HTTPException(404, "Keine robot.json konfiguriert (Datei fehlt oder ist ein Verzeichnis)")
    data = json.loads(_robot_json.read_text(encoding="utf-8"))
    return data.get("pose_estimation", {})


@_app.post("/v1/estimate")
async def estimate(
    images: List[UploadFile] = File(..., description="Kamerabilder (render_<id>.png)"),
    intrinsics: List[UploadFile] = File(..., description="Kamera-Intrinsiken (render_<id>.npz)"),
    robot_json: Optional[UploadFile] = File(default=None, description="robot.json (überschreibt Server-Konfig)"),
):
    """Pose-Schätzung aus Kamerabildern.

    Multipart-Upload:
      images[]    — render_a.png, render_b.png, ...
      intrinsics[] — render_a.npz, render_b.npz, ... (gleiche Reihenfolge)
      robot_json  — optional, überschreibt die Server-Konfiguration
    """
    with tempfile.TemporaryDirectory(prefix="approbot_req_") as tmp:
        tmp_path = Path(tmp)

        if robot_json is not None:
            rj_path = tmp_path / "robot.json"
            rj_path.write_bytes(await robot_json.read())
        elif _robot_json and _robot_json.is_file():
            rj_path = _robot_json
        else:
            raise HTTPException(400, "Keine robot.json angegeben (weder Upload noch gültige Server-Konfig)")

        for img in images:
            (tmp_path / img.filename).write_bytes(await img.read())
        for npz in intrinsics:
            (tmp_path / npz.filename).write_bytes(await npz.read())

        try:
            result = estimate_from_dir(tmp_path, robot_json=rj_path, eval_dir=tmp_path)
        except FileNotFoundError as exc:
            raise HTTPException(400, str(exc))
        except Exception as exc:
            raise HTTPException(500, str(exc))

    return JSONResponse({
        "joints": result.joints,
        "confidence": result.confidence,
        "residual_rms": result.residual_rms,
        "n_markers": result.n_markers,
        "processing_ms": result.processing_ms,
    })
