import puppeteer from 'puppeteer';
import { execSync } from 'child_process';
import { mkdirSync, rmSync, existsSync } from 'fs';
import path from 'path';
import { fileURLToPath } from 'url';

const __dirname = path.dirname(fileURLToPath(import.meta.url));
const FRAMES_DIR = path.join(__dirname, 'frames-16x9');
const OUTPUT = path.join(__dirname, 'promo-16x9.mp4');
const HTML_PATH = path.join(__dirname, 'video-16x9.html');

const FPS = 30;
const DURATION = 120; // 2 minutes
const TOTAL_FRAMES = FPS * DURATION;

// 1920x1080 Full HD 16:9
const WIDTH = 1920;
const HEIGHT = 1080;

async function wait(ms) {
  return new Promise(r => setTimeout(r, ms));
}

async function main() {
  if (existsSync(FRAMES_DIR)) rmSync(FRAMES_DIR, { recursive: true });
  mkdirSync(FRAMES_DIR, { recursive: true });

  console.log(`Recording ${DURATION}s at ${FPS}fps → ${TOTAL_FRAMES} frames`);
  console.log(`Resolution: ${WIDTH}×${HEIGHT}`);

  const browser = await puppeteer.launch({
    headless: true,
    args: ['--no-sandbox', '--disable-setuid-sandbox']
  });

  const page = await browser.newPage();
  await page.setViewport({ width: WIDTH, height: HEIGHT, deviceScaleFactor: 1 });

  await page.goto(`file://${HTML_PATH}`, { waitUntil: 'networkidle0' });
  await wait(500);

  // Pause all animations and the rAF timeline
  await page.evaluate(() => {
    // Stop the rAF loop
    window.__PAUSED = true;
    document.getAnimations().forEach(a => a.pause());
  });

  // Inject a function to manually advance the timeline
  await page.evaluate(() => {
    window.advanceTo = function(ms) {
      // Run timeline logic
      const TIMELINE = [
        [0, 's0', null],
        [2000, 's1', 'white'],
        [7000, 's2', 'white'],
        [10000, 's3', 'gold'],
        [14000, 's4', 'white'],
        [20000, 's5', 'white'],
        [25000, 's6', 'white'],
        [33000, 's7', 'gold'],
        [37000, 's8', 'white'],
        [45000, 's9', 'gold'],
        [49000, 's10', 'gold'],
        [54000, 's11', 'white'],
        [65000, 's12', 'white'],
        [73000, 's13', 'white'],
        [82000, 's14', 'white'],
        [90000, 's15', 'gold'],
        [97000, 's16', 'white'],
        [108000, 's17', 'gold'],
      ];

      let active = TIMELINE[0];
      for (const entry of TIMELINE) {
        if (ms >= entry[0]) active = entry;
        else break;
      }

      // Show scene
      document.querySelectorAll('.scene').forEach(s => s.classList.remove('active'));
      const el = document.getElementById(active[1]);
      if (el) el.classList.add('active');

      // Progress bar
      const prog = document.getElementById('prog');
      if (prog) prog.style.width = ((ms / 120000) * 100) + '%';

      // Advance CSS animations
      document.getAnimations().forEach(a => {
        a.currentTime = ms;
      });
    };
  });

  const msPerFrame = (DURATION * 1000) / TOTAL_FRAMES;

  for (let i = 0; i < TOTAL_FRAMES; i++) {
    const t = i * msPerFrame;

    await page.evaluate((time) => {
      window.advanceTo(time);
    }, t);

    await wait(10);

    const frameNum = String(i).padStart(5, '0');
    await page.screenshot({
      path: path.join(FRAMES_DIR, `frame_${frameNum}.png`),
      type: 'png'
    });

    if (i % 150 === 0) {
      console.log(`  Frame ${i}/${TOTAL_FRAMES} (${Math.round(t/1000)}s)`);
    }
  }

  await browser.close();
  console.log('Screenshots done. Encoding video...');

  const ffmpegCmd = [
    'ffmpeg', '-y',
    '-framerate', String(FPS),
    '-i', path.join(FRAMES_DIR, 'frame_%05d.png'),
    '-c:v', 'libx264',
    '-preset', 'medium',
    '-crf', '18',
    '-pix_fmt', 'yuv420p',
    OUTPUT
  ].join(' ');

  console.log(`Running ffmpeg...`);
  execSync(ffmpegCmd, { stdio: 'inherit' });

  rmSync(FRAMES_DIR, { recursive: true });

  console.log(`\n✅ Done! Video saved to: ${OUTPUT}`);
  console.log(`   Duration: ${DURATION}s, ${WIDTH}×${HEIGHT}, ${FPS}fps`);
}

main().catch(e => { console.error(e); process.exit(1); });
