#!/usr/bin/env python3
"""Render each slide of the Squad Film Golden Hour carousel as a 1080x1350 PNG."""
import http.server, socketserver, threading, time, sys, os
from pathlib import Path
from playwright.sync_api import sync_playwright

ROOT = Path(__file__).parent
OUT  = ROOT / "exports"
OUT.mkdir(exist_ok=True)

PORT = 8766

class Handler(http.server.SimpleHTTPRequestHandler):
    def __init__(self, *a, **k):
        super().__init__(*a, directory=str(ROOT), **k)
    def log_message(self, *a, **k): pass

class ReusableServer(socketserver.TCPServer):
    allow_reuse_address = True

httpd = ReusableServer(("127.0.0.1", PORT), Handler)
t = threading.Thread(target=httpd.serve_forever, daemon=True); t.start()
time.sleep(0.4)

URL = f"http://127.0.0.1:{PORT}/index.html"
TOTAL = 8

with sync_playwright() as p:
    browser = p.chromium.launch()
    ctx = browser.new_context(
        viewport={"width": 1300, "height": 1500},
        device_scale_factor=2,  # 2x for crisp PNG
    )
    page = ctx.new_page()
    page.on("console", lambda msg: print(f"[console.{msg.type}] {msg.text}"))
    page.on("pageerror", lambda err: print(f"[pageerror] {err}"))
    page.goto(URL, wait_until="networkidle")
    try:
        page.wait_for_selector(".slide-frame", timeout=10000)
    except Exception as e:
        print("HTML body snapshot:")
        print(page.content()[:2000])
        raise
    # force scale 1 by ensuring frame is 1080px (viewport math should give that)
    page.evaluate("""() => new Promise(res => {
        const tick = () => {
            document.querySelectorAll('.slide-frame').forEach(f => {
                f.style.width = '1080px';
                f.style.aspectRatio = '1080 / 1350';
                f.style.border = '0';
                f.style.boxShadow = 'none';
                f.style.setProperty('--slide-scale', 1);
            });
            // hide nav buttons / dots / tweaks panel for clean export
            const hideStyle = document.createElement('style');
            hideStyle.textContent = `
                .nav, .dots, .legend, .export-bar, .twk-panel, .twk-toggle { display: none !important; }
            `;
            document.head.appendChild(hideStyle);
            res();
        };
        if (document.fonts && document.fonts.ready) document.fonts.ready.then(tick); else tick();
    })""")
    # ensure all <img> loaded
    page.evaluate("""() => Promise.all(
        [...document.images].map(img => img.complete ? null : new Promise(r => {
            img.addEventListener('load', r);
            img.addEventListener('error', r);
        }))
    )""")
    time.sleep(0.4)

    frame = page.locator(".slide-frame").first

    for i in range(TOTAL):
        # navigate by mutating the carousel transform directly (dots are hidden now)
        page.evaluate(f"""(i) => {{
            const tracks = document.querySelectorAll('.slide-track');
            tracks.forEach(tr => {{
                tr.style.transform = `translateX(${{-i * 1080}}px)`;
                tr.style.transition = 'none';
            }});
        }}""", i)
        # wait for transition (700ms) + buffer
        page.wait_for_timeout(900)
        # ensure no scrollbar / layout reflow
        page.evaluate("""() => {
            document.querySelectorAll('.slide-frame').forEach(f => {
                f.style.width = '1080px';
                f.style.border = '0';
                f.style.boxShadow = 'none';
                f.style.setProperty('--slide-scale', 1);
            });
        }""")
        out = OUT / f"squad-golden-hour-{i+1:02d}.png"
        frame.screenshot(path=str(out), omit_background=False)
        print(f"  ✓ {out.name}")

    browser.close()

print(f"\nDone. Exports in: {OUT}")
