#!/usr/bin/env python3
"""Build a local scrub/timeline audit page for Phase A1 outputs."""

from __future__ import annotations

import argparse
import json
from pathlib import Path


HTML = """<!DOCTYPE html>
<html lang="zh-Hant">
<head>
<meta charset="utf-8"/>
<title>Glass A1 Audit — scrub + timeline</title>
<style>
  :root { --bg:#111; --fg:#eee; --work:#f0a000; --wait:#3ecf8e; --cycle:#ff5c5c; --gt:#6ea8fe; }
  * { box-sizing: border-box; }
  body { margin:0; font-family: ui-sans-serif, system-ui, sans-serif; background:var(--bg); color:var(--fg); }
  header { padding:12px 16px; border-bottom:1px solid #333; }
  main { display:grid; grid-template-columns: 1.4fr 1fr; gap:12px; padding:12px; }
  video { width:100%; background:#000; max-height:70vh; }
  .panel { background:#1a1a1a; border:1px solid #333; border-radius:8px; padding:12px; }
  .timeline { position:relative; height:84px; background:#0a0a0a; border:1px solid #333; margin-top:8px; }
  .lane { position:absolute; left:0; right:0; height:22px; }
  .lane.work { top:6px; }
  .lane.wait { top:32px; }
  .lane.cycle { top:58px; }
  .seg { position:absolute; top:2px; bottom:2px; border-radius:3px; cursor:pointer; opacity:0.85; }
  .seg.work { background:var(--work); }
  .seg.wait { background:var(--wait); }
  .seg.cycle { background:var(--cycle); }
  .seg.gt { outline:1px dashed var(--gt); background:transparent; border:1px solid var(--gt); }
  .playhead { position:absolute; top:0; bottom:0; width:2px; background:#fff; pointer-events:none; }
  .legend span { display:inline-block; margin-right:12px; font-size:12px; }
  .dot { display:inline-block; width:10px; height:10px; border-radius:2px; margin-right:4px; }
  ul { max-height:42vh; overflow:auto; padding-left:18px; }
  li { cursor:pointer; margin:4px 0; }
  li:hover { color:var(--gt); }
  .meta { font-size:13px; color:#bbb; }
</style>
</head>
<body>
<header>
  <strong>Phase A1 Audit</strong>
  <span class="meta" id="meta"></span>
</header>
<main>
  <section class="panel">
    <video id="v" controls preload="metadata" src="__VIDEO__"></video>
    <div class="legend" style="margin-top:8px">
      <span><i class="dot" style="background:var(--work)"></i>AI work</span>
      <span><i class="dot" style="background:var(--wait)"></i>AI wait</span>
      <span><i class="dot" style="background:var(--cycle)"></i>AI cycle</span>
      <span><i class="dot" style="border:1px solid var(--gt)"></i>GT markers</span>
    </div>
    <div class="timeline" id="tl">
      <div class="lane work" id="lane-work"></div>
      <div class="lane wait" id="lane-wait"></div>
      <div class="lane cycle" id="lane-cycle"></div>
      <div class="playhead" id="ph"></div>
    </div>
    <input id="seek" type="range" min="0" max="__DURATION__" value="0" style="width:100%; margin-top:8px"/>
  </section>
  <section class="panel">
    <h3 style="margin:0 0 8px">Events (click to seek)</h3>
    <div class="meta">t=0 on this page = wall __WALL0__ / video_abs __VT0__</div>
    <h4>AI cycles</h4>
    <ul id="cycles"></ul>
    <h4>GT load cycles (in window)</h4>
    <ul id="gt"></ul>
    <h4>AI wait intervals</h4>
    <ul id="waits"></ul>
  </section>
</main>
<script>
const DATA = __DATA__;
const DUR = __DURATION__;
const VT0 = __VT0__;
const v = document.getElementById('v');
const seek = document.getElementById('seek');
const ph = document.getElementById('ph');
document.getElementById('meta').textContent = ` frames=${DUR}s cycles=${DATA.cycles.length} work=${DATA.work_sec}s wait=${DATA.wait_sec}s`;

function pct(t){ return (t / DUR) * 100; }
function addSeg(lane, t0, t1, cls, title, seekT){
  const el = document.createElement('div');
  el.className = 'seg ' + cls;
  el.style.left = pct(t0) + '%';
  el.style.width = Math.max(0.15, pct(t1-t0)) + '%';
  el.title = title;
  el.onclick = () => { v.currentTime = seekT; };
  document.getElementById(lane).appendChild(el);
}
(DATA.work||[]).forEach(iv => addSeg('lane-work', iv.t0-VT0, iv.t1-VT0, 'work', `work ${iv.t0}-${iv.t1}`, iv.t0-VT0));
(DATA.wait||[]).forEach(iv => addSeg('lane-wait', iv.t0-VT0, iv.t1-VT0, 'wait', `wait ${iv.t0}-${iv.t1}`, iv.t0-VT0));
(DATA.cycles||[]).forEach(c => addSeg('lane-cycle', c.t_start, c.t_end, 'cycle', `cycle ${c.t_start_abs}-${c.t_end_abs}`, c.t_start));
(DATA.gt_cycles||[]).forEach(g => {
  const t = g.t - VT0;
  if (t < 0 || t > DUR) return;
  addSeg('lane-cycle', Math.max(0,t-2), Math.min(DUR,t+2), 'gt', `GT ${g.person} @${g.t}`, Math.max(0,t));
});

function li(parent, text, t){
  const el = document.createElement('li');
  el.textContent = text;
  el.onclick = () => { v.currentTime = t; };
  document.getElementById(parent).appendChild(el);
}
(DATA.cycles||[]).forEach((c,i)=> li('cycles', `#${i+1} local ${c.t_start}-${c.t_end}s abs ${c.t_start_abs}-${c.t_end_abs}`, c.t_start));
(DATA.gt_cycles||[]).forEach(g => {
  const t = g.t - VT0; if (t<0||t>DUR) return;
  li('gt', `${g.person} t_abs=${g.t} (${g.action.slice(0,40)})`, Math.max(0,t));
});
(DATA.wait||[]).forEach((iv,i)=> li('waits', `#${i+1} abs ${iv.t0}-${iv.t1}`, iv.t0-VT0));

function sync(){
  const t = v.currentTime || 0;
  seek.value = t;
  ph.style.left = pct(t) + '%';
}
v.addEventListener('timeupdate', sync);
seek.addEventListener('input', () => { v.currentTime = Number(seek.value); });
document.getElementById('tl').addEventListener('click', (e) => {
  const rect = e.currentTarget.getBoundingClientRect();
  const x = (e.clientX - rect.left) / rect.width;
  v.currentTime = x * DUR;
});
</script>
</body>
</html>
"""


def main() -> int:
    ap = argparse.ArgumentParser()
    ap.add_argument("--run-dir", required=True)
    ap.add_argument("--gt-json", required=True)
    ap.add_argument("--video-rel", default="overlay_1fps.mp4")
    ap.add_argument("--out-html", required=True)
    args = ap.parse_args()

    run = Path(args.run_dir)
    summary = json.loads((run / "summary.json").read_text(encoding="utf-8"))
    occ = json.loads((run / "occupancy_intervals.json").read_text(encoding="utf-8"))
    cycles = json.loads((run / "load_cycles.json").read_text(encoding="utf-8"))["cycles"]
    gt = json.loads(Path(args.gt_json).read_text(encoding="utf-8"))
    vt0 = int(summary["video_t0"])
    dur = int(summary["n_frames"])
    wall0_h = 8 + vt0 // 3600
    wall0_m = (vt0 % 3600) // 60
    data = {
        "cycles": cycles,
        "work": occ.get("work") or [],
        "wait": occ.get("wait") or [],
        "gt_cycles": gt.get("load_cycle_points") or [],
        "work_sec": summary.get("work_sec"),
        "wait_sec": summary.get("wait_sec"),
    }
    html = (
        HTML.replace("__VIDEO__", args.video_rel)
        .replace("__DURATION__", str(dur))
        .replace("__VT0__", str(vt0))
        .replace("__WALL0__", f"{wall0_h:02d}:{wall0_m:02d}")
        .replace("__DATA__", json.dumps(data, ensure_ascii=False))
    )
    out = Path(args.out_html)
    out.parent.mkdir(parents=True, exist_ok=True)
    out.write_text(html, encoding="utf-8")
    print(f"wrote {out}")
    return 0


if __name__ == "__main__":
    raise SystemExit(main())
