// Usage: node capture.mjs <loom-url> <out-dir> [intervalSeconds]
// Opens a Loom share/embed URL, plays it, captures a frame every N seconds,
// then builds a contact sheet via ffmpeg for fast scanning.

import { chromium } from 'playwright';
import { execSync } from 'node:child_process';
import fs from 'node:fs';
import path from 'node:path';

const rawUrl = process.argv[2];
const outDir = path.resolve(process.argv[3] || './frames');
const intervalSec = parseFloat(process.argv[4] || '3');

if (!rawUrl) {
  console.error('Usage: node capture.mjs <loom-url> <out-dir> [intervalSeconds]');
  process.exit(1);
}

// Convert /share/<id> -> /embed/<id>?autoplay=true so the real video loads
// instead of the 4-second preview clip Loom shows on share pages.
const m = rawUrl.match(/loom\.com\/(?:share|embed)\/([a-f0-9]+)/i);
const url = m
  ? `https://www.loom.com/embed/${m[1]}?autoplay=true&hideEmbedTopBar=true&hide_owner=true`
  : rawUrl;

fs.mkdirSync(outDir, { recursive: true });
// Clean old frames so the contact sheet doesn't pick them up
for (const f of fs.readdirSync(outDir)) {
  if (f.startsWith('frame-') || f === 'contact-sheet.jpg') fs.unlinkSync(path.join(outDir, f));
}

const browser = await chromium.launch({ headless: true });
const ctx = await browser.newContext({ viewport: { width: 1920, height: 1080 } });
const page = await ctx.newPage();

console.log(`Opening ${url}`);
await page.goto(url, { waitUntil: 'domcontentloaded', timeout: 60000 });
await page.waitForSelector('video', { timeout: 60000 });

// Force-mute and play
await page.evaluate(async () => {
  const v = document.querySelector('video');
  v.muted = true;
  try { await v.play(); } catch {}
});

// Poll until the real video metadata loads (preview clip is ~4s; real video >> 30s usually)
let realDuration = 0, realSrc = '';
for (let i = 0; i < 30; i++) {
  await page.waitForTimeout(1000);
  const { duration, src, readyState } = await page.evaluate(() => {
    const v = document.querySelector('video');
    return { duration: v.duration, src: v.currentSrc, readyState: v.readyState };
  });
  console.log(`  poll ${i}: dur=${duration?.toFixed(1)}s rs=${readyState} src=...${(src || '').slice(-50)}`);
  realDuration = duration;
  realSrc = src;
  if (Number.isFinite(duration) && duration > 15 && readyState >= 2) break;
}

if (!Number.isFinite(realDuration) || realDuration <= 0) {
  console.error('Could not read video duration. Last src:', realSrc);
  await browser.close();
  process.exit(2);
}

console.log(`\nUsing duration: ${realDuration.toFixed(1)}s, src: ${realSrc}`);

const steps = Math.floor(realDuration / intervalSec);
console.log(`Capturing ${steps + 1} frames at ${intervalSec}s intervals -> ${outDir}`);

for (let i = 0; i <= steps; i++) {
  const t = Math.min(i * intervalSec, realDuration - 0.1);
  await page.evaluate(
    (t) =>
      new Promise((resolve) => {
        const v = document.querySelector('video');
        v.pause();
        const onSeeked = () => { v.removeEventListener('seeked', onSeeked); resolve(); };
        v.addEventListener('seeked', onSeeked);
        v.currentTime = t;
      }),
    t,
  );
  await page.waitForTimeout(250);
  const file = path.join(outDir, `frame-${String(i).padStart(3, '0')}.png`);
  await page.locator('video').first().screenshot({ path: file });
  if ((i + 1) % 5 === 0 || i === steps) console.log(`  ${i + 1}/${steps + 1} (t=${t.toFixed(1)}s)`);
}

// Manifest mapping frame index -> seconds
const manifest = Array.from({ length: steps + 1 }, (_, i) => ({
  frame: `frame-${String(i).padStart(3, '0')}.png`,
  seconds: Math.min(i * intervalSec, realDuration - 0.1),
  mmss: (() => {
    const t = Math.min(i * intervalSec, realDuration - 0.1);
    const mm = Math.floor(t / 60).toString().padStart(2, '0');
    const ss = Math.floor(t % 60).toString().padStart(2, '0');
    return `${mm}:${ss}`;
  })(),
}));
fs.writeFileSync(path.join(outDir, 'manifest.json'), JSON.stringify(manifest, null, 2));

await browser.close();

// Contact sheet via ffmpeg using %03d sequence pattern (Windows-safe, no glob needed)
const cols = 6;
const rows = Math.ceil((steps + 1) / cols);
const sheet = path.join(outDir, 'contact-sheet.jpg');
const inPattern = path.join(outDir, 'frame-%03d.png').replace(/\\/g, '/');
console.log(`\nBuilding contact sheet (${cols}x${rows}): ${sheet}`);
execSync(
  `ffmpeg -y -framerate 1 -i "${inPattern}" -vf "scale=480:-1,tile=${cols}x${rows}" "${sheet.replace(/\\/g, '/')}"`,
  { stdio: 'inherit' },
);
console.log('Done.');
