#!/usr/bin/env python3
"""JUDGE GERAL de composição do-zero -> judge_switches_ok.json. Pra cada segmento >=5s do UNI:
frame da ATIVA + das alternativas cobertas no meio -> VLM mantém ou troca (default manter).
Uso: switch_judge_gen.py [--limit N]"""
import json, os, sys
from vlm import ask_images, par_map
import judgelib as J
import vlib as V
import cache_manifest as cm

OUT = "judge_switches_ok.json"
_SCRIPT_DIR = os.path.dirname(os.path.abspath(__file__))

def main():
    limit = int(sys.argv[sys.argv.index("--limit")+1]) if "--limit" in sys.argv else 10**9
    # CACHE (backlog-30 grupo2): o mais caro dos judges — 1 call/segmento >=5s, ~84% do wall
    # time do cut. UNI.json/storyboard.json são REESCRITOS pelo unified.py pass0/storyboard_gen
    # toda rodada (byte-idênticos quando nada muda, mas mtime novo) -> content_signature, não
    # input_signature. extra_deps=["storyboard_gen"]: se o storyboard rodou de novo depois do
    # meu último mark_done, meu veredito pode estar obsoleto mesmo com os mesmos bytes de UNI.
    _sig = {"content": cm.content_signature(["versions/UNI.json", "storyboard.json"]),
            "mtime": cm.input_signature(["placements.json",
                                          os.path.join(_SCRIPT_DIR, "prompts", "switch_judge_v1.md"),
                                          os.path.join(_SCRIPT_DIR, "judgelib.py"),
                                          os.path.join(_SCRIPT_DIR, "vlib.py")]),
            "limit": limit}
    if cm.is_fresh(".", "switch_judge_gen", __file__, _sig, extra_deps=["storyboard_gen"]) \
            and os.path.exists(OUT):
        print(f"[cache] switch_judge_gen: script+input inalterados, pulando VLM — reusando {OUT}")
        return
    cov = V.coverage()
    beat = J.beat_fn()
    prompt = J.prompt("switch_judge_v1.md")
    segs = [s for s in J.uni_segments(min_dur_s=5)][:limit]
    def work(ie):
        i, s = ie
        mid = (s["f0"]+s["f1"])//2
        alts = [a for a in sorted(V.ANGLE_CAM) if a != s["angle"] and V.covers(cov, a, s["f0"], s["f1"])]
        if not alts: return None
        imgs = [J.frame_of(s["angle"], mid)] + [J.frame_of(a, mid) for a in alts]
        if not all(imgs): return None
        b, _ = beat(mid)
        txt, _ = ask_images(imgs, prompt.replace("{BEAT}", b))
        v = J.jparse(txt)
        if v.get("switch") and float(v.get("confidence", 0) or 0) >= 0.7:
            to = alts[min(max(int(v.get("to", 1))-1, 0), len(alts)-1)]
            print(f"  [{i+1}/{len(segs)}] {J.tc(s['f0'])} {b}: cam{s['angle']}->cam{to} ({v.get('why','')[:50]})")
            return {"tc": J.tc(s["f0"])+":00", "active": s["angle"], "to_cam": to,
                    "confidence": round(float(v["confidence"]), 2), "f0": s["f0"], "f1": s["f1"], "idx": i}
        return None
    out = [r for r in par_map(work, list(enumerate(segs))) if r]
    json.dump(out, open(OUT, "w"), indent=1)
    cm.mark_done(".", "switch_judge_gen", __file__, _sig)
    print(f"judge_switches_ok.json: {len(out)} trocas de {len(segs)} segmentos")

if __name__ == "__main__":
    main()
