#!/usr/bin/env python3
"""
Renderiza HTML animado como vídeo silencioso.
Estratégia: real-time capture. Chama window.__START() e captura screenshots
ao longo da linha do tempo real. Após capturar, retima com ffmpeg setpts para
garantir duração-alvo exata.
"""
import os, sys, time, subprocess, argparse, math
from pathlib import Path
from playwright.sync_api import sync_playwright

def main():
    ap = argparse.ArgumentParser()
    ap.add_argument("--html", required=True)
    ap.add_argument("--out", required=True)
    ap.add_argument("--width", type=int, default=1080)
    ap.add_argument("--height", type=int, default=1920)
    ap.add_argument("--fps", type=int, default=30)
    ap.add_argument("--duration-ms", type=int, default=50500)
    ap.add_argument("--frames-dir", default=None)
    args = ap.parse_args()

    html_path = Path(args.html).resolve()
    out_mp4 = Path(args.out).resolve()
    out_mp4.parent.mkdir(parents=True, exist_ok=True)
    frames_dir = Path(args.frames_dir) if args.frames_dir else out_mp4.parent / f"_frames_{out_mp4.stem}"
    frames_dir.mkdir(parents=True, exist_ok=True)
    for f in frames_dir.glob("*.png"):
        f.unlink()

    total_frames = int(args.fps * (args.duration_ms / 1000))
    frame_interval = 1.0 / args.fps
    duration_s = args.duration_ms / 1000.0
    print(f"[render] {total_frames} frames @ {args.fps}fps, {args.width}x{args.height} ({duration_s:.1f}s)")

    with sync_playwright() as p:
        browser = p.chromium.launch(headless=True, args=[
            '--disable-web-security',
            '--allow-file-access-from-files',
            '--no-sandbox',
            '--font-render-hinting=none',
            '--disable-blink-features=AutomationControlled',
        ])
        ctx = browser.new_context(
            viewport={'width': args.width, 'height': args.height},
            device_scale_factor=1,
        )
        page = ctx.new_page()
        page.goto(f"file://{html_path}?record=1", wait_until="load")
        page.evaluate("() => document.fonts.ready")
        page.wait_for_load_state('networkidle', timeout=15000)
        time.sleep(2.0)  # aguarda fontes e imagens

        # dispara animação
        page.evaluate("() => window.__START && window.__START()")
        anim_start = time.time()

        captured = 0
        target_times = [i * frame_interval for i in range(total_frames)]
        for i, target_t in enumerate(target_times):
            # espera até bater o timestamp alvo (relativo ao anim_start)
            now_t = time.time() - anim_start
            wait = target_t - now_t
            if wait > 0:
                time.sleep(wait)
            elif wait < -0.15:
                # atrasou muito, pula esse frame (usa último)
                pass
            frame_path = frames_dir / f"frame_{i:05d}.png"
            try:
                page.screenshot(path=str(frame_path), type='png',
                               clip={'x':0,'y':0,'width':args.width,'height':args.height},
                               timeout=8000)
                captured += 1
            except Exception as e:
                print(f"  [err frame {i}] {e}")
                # copia frame anterior
                if i > 0:
                    prev = frames_dir / f"frame_{i-1:05d}.png"
                    if prev.exists():
                        import shutil
                        shutil.copy(prev, frame_path)
                        captured += 1
            if i % 30 == 0:
                elapsed = time.time() - anim_start
                lag = elapsed - target_t
                print(f"  frame {i}/{total_frames} target={target_t:.2f}s actual={elapsed:.2f}s lag={lag:.2f}s")
        browser.close()

    print(f"[render] {captured}/{total_frames} frames capturados")

    # ffmpeg: força fps declarado -> duração exata
    cmd = [
        'ffmpeg', '-y', '-framerate', str(args.fps),
        '-i', str(frames_dir / 'frame_%05d.png'),
        '-c:v', 'libx264', '-pix_fmt', 'yuv420p',
        '-preset', 'medium', '-crf', '18',
        '-vf', f'fps={args.fps}',
        '-movflags', '+faststart',
        str(out_mp4)
    ]
    print(f"[ffmpeg] montando MP4...")
    subprocess.run(cmd, check=True, capture_output=True)
    # duração real
    dur = subprocess.check_output(['ffprobe','-v','error','-show_entries','format=duration',
                                   '-of','default=noprint_wrappers=1:nokey=1', str(out_mp4)]).decode().strip()
    print(f"[done] {out_mp4} ({dur}s)")

if __name__ == '__main__':
    main()
