#!/usr/bin/env python3
from pathlib import Path
import subprocess, json, glob, os, shlex
BASE=Path('/home/kevin/shared/video-packs/ia-tomo-control-V1-production')
SEG=BASE/'segments/rough-v1'; SEG.mkdir(parents=True, exist_ok=True)
VIDEO=BASE/'video'; VIDEO.mkdir(exist_ok=True)

def run(cmd):
    print('RUN', ' '.join(shlex.quote(str(c)) for c in cmd), flush=True)
    subprocess.run(cmd, check=True)

def dur(path):
    p=subprocess.run(['ffprobe','-v','error','-show_entries','format=duration','-of','default=nw=1:nk=1',str(path)],capture_output=True,text=True,check=True)
    return float(p.stdout.strip())

def first(patterns):
    for pat in patterns:
        xs=sorted(glob.glob(str(pat)))
        if xs: return Path(xs[0])
    return None
segments=[]
for i in range(1,10):
    sid=f's{i:02d}'
    audio=first([BASE/f'assets/runway-visual-voice/{sid}-voiceover-*.mp3', BASE/f'assets/runway-gateway/{sid}-voiceover-*.mp3'])
    if not audio:
        raise SystemExit(f'missing voiceover {sid}')
    # Prefer Runway motion visual, fallback to measured styleframe then Image2 key visual.
    visual=first([BASE/f'assets/runway-visual-voice/{sid}-visual-*.mp4', BASE/f'assets/runway-gateway/{sid}-visual-*.mp4'])
    still=BASE/f'assets/styleframes-v2/styleframe-{i:02d}-measured-text-v2.png'
    if not still.exists(): still=first([BASE/f'assets/image2-scenes/scene-{i:02d}-*.png'])
    ad=dur(audio)
    out=SEG/f'{sid}.mp4'
    if visual and visual.exists():
        # loop visual to audio duration, overlay measured styleframe text subtly? For rough, use styleframe still for text safety.
        run(['ffmpeg','-y','-v','error','-stream_loop','-1','-i',str(visual),'-i',str(audio),'-t',f'{ad:.3f}',
             '-vf','scale=1920:1080:force_original_aspect_ratio=increase,crop=1920:1080,setsar=1,fps=25',
             '-c:v','libx264','-preset','veryfast','-crf','18','-c:a','aac','-b:a','256k','-ar','48000','-ac','1','-shortest',str(out)])
    else:
        run(['ffmpeg','-y','-v','error','-loop','1','-i',str(still),'-i',str(audio),'-t',f'{ad:.3f}',
             '-vf',"scale=1920:1080,setsar=1,zoompan=z='min(zoom+0.00035,1.045)':d=1:x='iw/2-(iw/zoom/2)':y='ih/2-(ih/zoom/2)':s=1920x1080:fps=25",
             '-c:v','libx264','-preset','veryfast','-crf','18','-c:a','aac','-b:a','256k','-ar','48000','-ac','1','-shortest',str(out)])
    segments.append(out)
concat=SEG/'concat.txt'
concat.write_text(''.join(f"file '{p}'\n" for p in segments))
out=VIDEO/'ia-tomo-control-rough-v1-no-avatar-motionarray-pending.mp4'
run(['ffmpeg','-y','-v','error','-f','concat','-safe','0','-i',str(concat),'-c','copy',str(out)])
# validate
run(['ffmpeg','-nostdin','-v','error','-i',str(out),'-f','null','-'])
meta={'output':str(out),'duration':dur(out),'segments':[str(p) for p in segments], 'status':'ROUGH_NOT_FINAL', 'missing':'avatar clips + MotionArray final selection + final QA'}
(BASE/'manifests/rough-v1-build.json').write_text(json.dumps(meta,indent=2,ensure_ascii=False))
print(json.dumps(meta,indent=2,ensure_ascii=False))
