# -*- coding: utf-8 -*-
"""End-to-end multi-clip test through the real API.

Two segments cut from the known ride: seg1 = video 0..100s, seg2 = video
130..220s (30s un-recorded gap in between). Known ground truth:
  seg1 starts at real clock 08:57:01  (original sync anchor)
  seg2 starts at real clock 08:59:11  (08:57:01 + 130s)
So the composite window should show the FIT data jumping across the gap at
output t=100, and stats should cover ~190s of riding.
"""
import json
import sys
import time
import urllib.request

sys.stdout.reconfigure(encoding="utf-8")
BASE = "http://127.0.0.1:8765"


def post(path, payload):
    req = urllib.request.Request(BASE + path, data=json.dumps(payload).encode(),
                                 method="POST",
                                 headers={"Content-Type": "application/json"})
    return json.loads(urllib.request.urlopen(req).read())


def get(path):
    return json.loads(urllib.request.urlopen(BASE + path).read())


print("① 建立雙片段專案")
p = post("/api/projects", {
    "video_paths": [r"C:\ai\AUTOMOVIE\spikes\multiclip\seg1.mp4",
                    r"C:\ai\AUTOMOVIE\spikes\multiclip\seg2.mp4"],
    "fit_path": r"C:\ai\AUTOMOVIE\濕背約騎-里嶺_-美濃-茂林_里嶺.fit"})
pid = p["id"]
print(f"   id={pid}  片段={len(p['clips'])}  總長={p['video']['duration']:.1f}s")
assert len(p["clips"]) == 2
assert abs(p["video"]["duration"] - 190.2) < 1.0

print("② 對時片段1（已知 t=10 → 08:57:11）")
r1 = post(f"/api/p/{pid}/sync", {"video_t": 10, "clock": "08:57:11", "clip": 0})
print(f"   clips_synced={r1['clips_synced']}  all={r1['all_synced']}")
assert not r1["all_synced"]

print("③ 對時片段2（已知 seg2 的 t=10 → 08:59:21）")
r2 = post(f"/api/p/{pid}/sync", {"video_t": 10, "clock": "08:59:21", "clip": 1})
print(f"   clips_synced={r2['clips_synced']}  all={r2['all_synced']}")
assert r2["all_synced"]
s = r2["stats"]
print(f"   複合窗口: {s['records']} 筆  {s['dist_km']} km  "
      f"均速 {s['spd_kmh']['avg']}  心率 {s['hr']['avg']}")

print("④ 驗證窗口在段落交界的時間跳躍（output t=99 vs t=101）")
win = json.loads((__import__('pathlib').Path(
    rf"C:\ai\AUTOMOVIE\app\projects\{pid}\window.json")).read_text(
    encoding="utf-8"))
by_vt = {round(r["vt"]): r for r in win}
a, b = by_vt.get(99), by_vt.get(101)
print(f"   t=99  → 真實時間 {a['t'][11:19]}   (應為 08:58:4x)")
print(f"   t=101 → 真實時間 {b['t'][11:19]}   (應為 08:59:1x，跳過30秒空檔)")
assert a["t"][11:16] == "08:58" and b["t"][11:16] == "08:59"

print("⑤ 抽圖（use_ai=false，驗證多段抽圖與時間軸）")
job = post(f"/api/p/{pid}/analyze", {"interval": 10, "use_ai": False})["job"]
for _ in range(60):
    time.sleep(2)
    j = get(f"/api/job/{job}")
    if j["status"] != "running":
        break
assert j["status"] == "done", j["log"][-3:]
pr = get(f"/api/p/{pid}")
ts = [f["t"] for f in pr["frames"]]
files = {f["t"]: f["file"] for f in pr["frames"]}
print(f"   {len(ts)} 張，t 範圍 {min(ts)}~{max(ts)}")
print(f"   t=90 → {files.get(90)}   t=100 → {files.get(100)}")
assert files.get(90, "").startswith("c0/")
assert files.get(100, "").startswith("c1/")

print("⑥ 規則法產生旁白（不花 AI）")
job = post(f"/api/p/{pid}/script/generate", {"use_ai": False, "density": 20})["job"]
for _ in range(60):
    time.sleep(2)
    j = get(f"/api/job/{job}")
    if j["status"] != "running":
        break
assert j["status"] == "done", j["log"][-3:]
script = get(f"/api/p/{pid}/script")
print(f"   {len(script)} 句，最後一句 @ {script[-1]['start']}s")
assert script[-1]["start"] < 191

print("⑦ 轉檔（720p，含儀表盤+時鐘，驗證 concat 與時間跳躍）")
job = post(f"/api/p/{pid}/render", {
    "resolution": "720p", "encoder": "auto", "music": True,
    "voice": "zh-TW-YunJheNeural",
    "dashboard": {"enabled": True, "speed": True, "hr": True, "cad": True,
                  "grad": True, "clock": True, "title": "雙片段合併測試"}})["job"]
t0 = time.time()
for _ in range(300):
    time.sleep(5)
    j = get(f"/api/job/{job}")
    if j["status"] != "running":
        break
print(f"   狀態={j['status']}  耗時 {time.time()-t0:.0f}s")
if j["status"] != "done":
    print("\n".join(j["log"][-6:]))
    raise SystemExit(1)
print("   ✅ 全部通過")
print(f"\npid={pid}")
