"""
AIR Blackbox Episode Replay UI.

Adds a /replay view to the dashboard: a timeline of recorded runs with a
detail panel showing model, provider, tokens, checksums, vault references,
and live audit chain verification status from the gateway.

Run standalone:  python3 dashboard/replay.py  (port 8090)
Or mount into any FastAPI app:  app.include_router(replay.router)
"""

import glob
import json
import os
from pathlib import Path

import httpx
from fastapi import APIRouter, HTTPException, Request
from fastapi.responses import HTMLResponse, JSONResponse
from fastapi.templating import Jinja2Templates

router = APIRouter()

RUNS_DIR = os.environ.get("RUNS_DIR", "./runs")
GATEWAY_URL = os.environ.get("GATEWAY_URL", "http://localhost:8080")

templates = Jinja2Templates(directory=str(Path(__file__).parent / "templates"))


def _load_runs(limit: int = 500) -> list[dict]:
    """Load AIR records, newest first."""
    pattern = os.path.join(RUNS_DIR, "**", "*.air.json")
    paths = glob.glob(pattern, recursive=True)
    paths.sort(key=os.path.getmtime, reverse=True)

    runs = []
    for p in paths[:limit]:
        try:
            with open(p) as f:
                runs.append(json.load(f))
        except (json.JSONDecodeError, OSError):
            continue  # skip partial/corrupt records, never crash the UI
    return runs


async def _chain_status() -> dict:
    """Fetch live audit chain verification from the gateway."""
    try:
        async with httpx.AsyncClient(timeout=3.0) as client:
            resp = await client.get(f"{GATEWAY_URL}/v1/audit")
            if resp.status_code == 200:
                data = resp.json()
                return {
                    "available": True,
                    "chain_valid": data.get("chain_valid"),
                    "chain_length": data.get("chain_length"),
                    "chain_broken_at": data.get("chain_broken_at"),
                    "chain_error": data.get("chain_error"),
                }
    except httpx.HTTPError:
        pass
    return {"available": False}


@router.get("/", include_in_schema=False)
async def root_redirect():
    """Friendly root: send visitors to the replay UI."""
    from fastapi.responses import RedirectResponse
    return RedirectResponse(url="/replay")


@router.get("/replay", response_class=HTMLResponse)
async def replay_page(request: Request):
    """Render the episode replay UI."""
    # Rendered directly so this works across Starlette versions, which
    # changed the TemplateResponse argument order.
    html = templates.get_template("replay.html").render()
    return HTMLResponse(html)


@router.get("/api/runs", response_class=JSONResponse)
async def api_runs(limit: int = 200):
    """List recorded runs, newest first, with chain status."""
    return {
        "runs": _load_runs(limit=min(limit, 500)),
        "chain": await _chain_status(),
    }


@router.get("/api/run/{run_id}", response_class=JSONResponse)
async def api_run(run_id: str):
    """Single run detail by run_id."""
    # Run IDs are UUIDs generated by the gateway. Reject anything that could
    # be a path traversal attempt before touching the filesystem.
    safe = run_id.replace("-", "").isalnum()
    if not safe or len(run_id) > 64:
        raise HTTPException(status_code=400, detail="invalid run id")

    matches = glob.glob(
        os.path.join(RUNS_DIR, "**", f"{run_id}.air.json"), recursive=True
    )
    if not matches:
        raise HTTPException(status_code=404, detail="run not found")
    try:
        with open(matches[0]) as f:
            record = json.load(f)
    except (json.JSONDecodeError, OSError):
        raise HTTPException(status_code=500, detail="record unreadable")

    return {"run": record, "chain": await _chain_status()}


# --- Standalone mode -------------------------------------------------------
# The router above can be mounted into any FastAPI app. When run directly,
# it serves as its own small app:  python3 dashboard/replay.py
from fastapi import FastAPI

app = FastAPI(title="AIR Blackbox Episode Replay")
app.include_router(router)

if __name__ == "__main__":
    import uvicorn

    port = int(os.environ.get("REPLAY_PORT", "8090"))
    uvicorn.run(app, host="127.0.0.1", port=port)
