#!/usr/bin/env python3
"""CONTENT-INSERTS do-zero (holds-flat) -> content_inserts.json. Localizador: hold >=12s do UNI ∩
cluster >=3 hits do content_map_dense na ALT (> ativa) -> judge Kimi confirma; sub-span 4s nas
bordas do conteúdo. Uso: content_gen.py"""
import json, os, collections
from vlm import ask_images, par_map
import judgelib as J
import vlib as V
import cache_manifest as cm

FPS = 30
KEYS = {"orquestra", "musicos", "sax", "flauta", "violino", "publico_assistindo", "reacao_publico",
        "celebrante_close", "corredor_nave", "corredor_movimento", "aplausos"}
OUT = "content_inserts.json"
_SCRIPT_DIR = os.path.dirname(os.path.abspath(__file__))

def main():
    # CACHE (backlog-30 grupo2): ~44 agentes/run. UNI.json/content_map_dense.json/storyboard.json
    # são regenerados pelo pipeline toda rodada (byte-idênticos quando nada muda, mtime novo) ->
    # content_signature. extra_deps=["gen_content_map"]: cinto-e-suspensório sobre o content-hash
    # (gen_content_map.py ainda não é estágio cacheado hoje — dep_entry vem None e o check vira
    # no-op — mas fica pronto se/quando ele ganhar cache_manifest próprio).
    _sig = {"content": cm.content_signature(["versions/UNI.json", "content_map_dense.json",
                                              "storyboard.json"]),
            "mtime": cm.input_signature([os.path.join(_SCRIPT_DIR, "prompts", "content_judge_v1.md"),
                                          os.path.join(_SCRIPT_DIR, "judgelib.py"),
                                          os.path.join(_SCRIPT_DIR, "vlib.py")])}
    if cm.is_fresh(".", "content_gen", __file__, _sig, extra_deps=["gen_content_map"]) \
            and os.path.exists(OUT):
        print(f"[cache] content_gen: script+input inalterados, pulando VLM — reusando {OUT}")
        return
    cov = V.coverage()
    cmap = [h for h in json.load(open("content_map_dense.json")) if h["key"] in KEYS]
    prompt = J.prompt("content_judge_v1.md")
    def work(s):
        byalt = collections.defaultdict(list)
        for h in cmap:
            an = V.CAM_ANGLE[h["cam"]]
            if an != s["angle"] and s["f0"] <= h["f"] < s["f1"]: byalt[(an, h["key"])].append(h)
        best = None
        for (an, key), hs in byalt.items():
            if len(hs) >= 3 and V.covers(cov, an, s["f0"], s["f1"]):
                sc = max(h["score"] for h in hs)
                if not best or sc > best[2]: best = (an, key, sc, hs)
        if not best: return None
        an, key, sc, hs = best
        peak = max(hs, key=lambda h: h["score"])["f"]
        f0 = max(s["f0"], peak - 2*FPS); f1 = min(s["f1"], f0 + 4*FPS)
        a = J.frame_of(an, peak); b = J.frame_of(s["angle"], peak)
        if not a or not b: return None
        txt, _ = ask_images([a, b], prompt.replace("{KEY}", key))
        v = J.jparse(txt)
        st = "KEEP" if v.get("keep") else "drop"
        print(f"  {J.tc(f0)} hold cam{s['angle']} + {key}@cam{an} -> {st} ({str(v.get('why',''))[:50]})")
        if not v.get("keep"): return None
        return {"f0": int(f0), "f1": int(f1), "angle": an, "to_cam": an, "tc": J.tc(f0)[:8],
                "dur": round((f1-f0)/FPS, 1), "conf": 0.7, "content": f"{key}: {v.get('why','')[:80]}"}
    out = [r for r in par_map(work, list(J.uni_segments(min_dur_s=12))) if r]
    json.dump(out, open(OUT, "w"), indent=1)
    cm.mark_done(".", "content_gen", __file__, _sig)
    print(f"content_inserts.json: {len(out)} inserts")

if __name__ == "__main__":
    main()
