#!/usr/bin/env python3
"""Compose estilo REEL (DZacRyDCt0z): captions de FRASE limpia + GRÁFICAS DE DATO animadas
sobre la cara (overlays MOV con alpha) + b-rolls premium con corte snappy. Sin word-by-word."""
import subprocess, pathlib, sys
sys.path.insert(0, "/home/clawd/bin/agentsquad-shorts")
from lib import captions

BASE = "/home/clawd/playgrounds/ai4m-dirigir"
AV = f"{BASE}/avatar.mp4"
BROLL = f"{BASE}/brolls"
WORK = pathlib.Path("/tmp/ai4m-dir-dyn2"); WORK.mkdir(exist_ok=True)
OUTF = f"{BASE}/final_dyn2.mp4"
CARTEL = f"{BASE}/cartel.png"
BAND = 220

BEATS = [
    {"clip": f"{BROLL}/sora.mp4",        "start": 4.0,  "end": 8.0},
    {"clip": f"{BROLL}/caminos.mp4",     "start": 25.5, "end": 33.5},
    {"clip": f"{BROLL}/herramienta.mp4", "start": 48.5, "end": 56.5},
    {"clip": f"{BROLL}/senales.mp4",     "start": 64.5, "end": 75.5},
]
# overlays de dato (MOV alpha) sobre la cara, en huecos sin b-roll
DATA = [
    {"clip": f"{BROLL}/ov_anios.mov",   "start": 13.7, "end": 17.1},   # "...importar en 5 años"
    {"clip": f"{BROLL}/ov_agentes.mov", "start": 33.7, "end": 37.1},   # "Dirijo 16 agentes"
]
sup = [(b["start"], b["end"]) for b in BEATS]

def run(cmd):
    r = subprocess.run(cmd, capture_output=True, text=True)
    if r.returncode != 0:
        raise RuntimeError(f"FAILED: {' '.join(map(str,cmd))}\n{r.stderr[-1800:]}")

print("captions de frase (build_ass)...")
words = captions.transcribe_words(AV)
SCRIPT_TXT = open(f"{BASE}/script.txt").read().strip()
words = captions.align_to_script(words, SCRIPT_TXT)
def fix_brand(ws):
    out=[]; i=0
    while i < len(ws):
        w=ws[i]; wl=str(w.get("word","")).strip().lower().strip(".,!?")
        if wl=="ai" and i+2<len(ws):
            w1=str(ws[i+1].get("word","")).strip().lower().strip(".,!?")
            w2raw=str(ws[i+2].get("word","")).strip(); w2=w2raw.lower().strip(".,!?")
            if w1 in ("for","form","four","fore") and w2.startswith("manager"):
                trail="." if w2raw.endswith(".") else ""
                out.append({"word":"AI4Managers"+trail,"start":float(w.get("start",0)),"end":float(ws[i+2].get("end",0))}); i+=3; continue
        out.append(w); i+=1
    return out
words=fix_brand(words)
ass = WORK/"phrase.ass"
captions.build_ass(words, ass, margin_v=360, suppress_windows=sup)

print("audio...")
audio_norm = WORK/"audio.m4a"
run(["ffmpeg","-y","-i",AV,"-vn","-af","loudnorm=I=-16:TP=-1.5","-ar","44100","-c:a","aac","-b:a","192k",str(audio_norm)])

print("b-rolls...")
for i,b in enumerate(BEATS):
    run(["ffmpeg","-y","-i",b["clip"],"-vf","scale=1080:1920:force_original_aspect_ratio=increase,crop=1080:1920,fps=30,setsar=1","-an",str(WORK/f"fill{i}.mp4")])

print("componiendo (cartel + captions de frase + overlays de dato + b-rolls)...")
inputs=["-i",AV]
for i in range(len(BEATS)): inputs+=["-i",str(WORK/f"fill{i}.mp4")]
for d in DATA: inputs+=["-i",d["clip"]]
inputs+=["-i",str(audio_norm),"-i",CARTEL]
nb=len(BEATS); nd=len(DATA)
cartel_idx = 1+nb+nd+1   # avatar(0) + b-rolls + data + audio + cartel
audio_in = 1+nb+nd
parts=[
    f"[0:v]scale=1080:1920:force_original_aspect_ratio=increase,crop=1080:1920,fps=30,setsar=1,"
    f"pad=1080:{1920+BAND}:0:{BAND}:color=0x0a0a0a,crop=1080:1920:0:0[shift]",
    f"[shift][{cartel_idx}:v]overlay=0:0[carteled]",
    f"[carteled]subtitles={ass}[base]",
]
# data overlays (MOV alpha) sobre la cara
base="[base]"
for j,d in enumerate(DATA):
    idx=1+nb+j; dur=d["end"]-d["start"]
    parts.append(f"[{idx}:v]setpts=PTS+{d['start']:.2f}/TB[ovd{j}]")
    lbl=f"[db{j}]"
    parts.append(f"{base}[ovd{j}]overlay=0:0:enable='between(t,{d['start']:.2f},{d['end']:.2f})'{lbl}")
    base=lbl
# b-rolls full-screen, corte snappy (sin fade-in; fade-out corto)
for i,b in enumerate(BEATS):
    dur=b["end"]-b["start"]
    parts.append(f"[{i+1}:v]fade=t=out:st={dur-0.12:.2f}:d=0.12:alpha=1,setpts=PTS+{b['start']:.2f}/TB[ov{i}]")
for i,b in enumerate(BEATS):
    lbl="[v]" if i==len(BEATS)-1 else f"[c{i}]"
    parts.append(f"{base}[ov{i}]overlay=0:0:enable='between(t,{b['start']:.2f},{b['end']:.2f})'{lbl}")
    base=lbl
fc=";".join(parts)
run(["ffmpeg","-y",*inputs,"-filter_complex",fc,"-map","[v]","-map",f"{audio_in}:a",
     "-c:v","libx264","-preset","veryfast","-crf","19","-pix_fmt","yuv420p","-c:a","copy","-movflags","+faststart",OUTF])
dur=subprocess.check_output(["ffprobe","-v","error","-show_entries","format=duration","-of","csv=p=0",OUTF]).decode().strip()
print(f"OK -> {OUTF} ({float(dur):.1f}s)")
