#!/usr/bin/env node
/**
 * tools/adaptive-smoke.mjs — empirically trigger the adaptive-quality downstep.
 *
 * Loads a heavy sample in headless Chrome (software GL = slow) + applies a CDP
 * CPU throttle so the REAL measured fps sustains < 60. Captures the genuine
 * `[hmwebviewer] adaptive quality -> tier N (pr=..)` console logs emitted by
 * src/viewer/adaptiveQuality.ts, plus the live #.fps overlay text. Proves the
 * <60fps → optimize path fires on real frame measurement (no logic patched).
 *
 * USAGE: node tools/adaptive-smoke.mjs [--url URL] [--asset PATH] [--throttle N] [--seconds S]
 */
import puppeteer from 'puppeteer-core';
import { existsSync } from 'node:fs';

const CHROME_CANDIDATES = [
  'C:/Program Files/Google/Chrome/Application/chrome.exe',
  'C:/Program Files (x86)/Google/Chrome/Application/chrome.exe',
  'C:/Program Files (x86)/Microsoft/Edge/Application/msedge.exe',
];
function findBrowser() {
  if (process.env.PUPPETEER_EXECUTABLE_PATH && existsSync(process.env.PUPPETEER_EXECUTABLE_PATH)) return process.env.PUPPETEER_EXECUTABLE_PATH;
  for (const p of CHROME_CANDIDATES) if (existsSync(p)) return p;
  return null;
}

function parseArgs(argv) {
  const a = argv.slice(2);
  let url = 'http://127.0.0.1:4173', asset = '/samples/ABeautifulGame.ktx2.glb', throttle = 6, seconds = 25;
  for (let i = 0; i < a.length; i++) {
    if (a[i] === '--url') url = a[++i];
    else if (a[i] === '--asset') asset = a[++i];
    else if (a[i] === '--throttle') throttle = Number(a[++i]);
    else if (a[i] === '--seconds') seconds = Number(a[++i]);
  }
  return { url, asset, throttle, seconds };
}

const sleep = (ms) => new Promise((r) => setTimeout(r, ms));

async function main() {
  const o = parseArgs(process.argv);
  const exe = findBrowser();
  if (!exe) { console.error('[adaptive-smoke] No Chrome/Edge found.'); process.exit(1); }

  const browser = await puppeteer.launch({
    executablePath: exe,
    headless: 'new',
    args: ['--no-sandbox', '--use-gl=swiftshader', '--enable-webgl', '--ignore-gpu-blocklist'],
  });
  const page = await browser.newPage();

  const tierLogs = [];
  page.on('console', (m) => {
    const t = m.text();
    if (t.includes('adaptive quality')) { tierLogs.push(t); console.log('  LOG ' + t); }
  });

  await page.evaluateOnNewDocument(() => {
    window.__hmwReady = null;
    window.addEventListener('hmw:ready', (e) => { window.__hmwReady = e.detail; });
  });

  const target = o.url + '?model=' + o.asset;
  console.log('[adaptive-smoke] ' + target + '  throttle=' + o.throttle + 'x  watch=' + o.seconds + 's  browser=' + exe);
  await page.goto(target, { waitUntil: 'domcontentloaded', timeout: 30000 });
  await page.waitForFunction('window.__hmwReady != null', { timeout: 60000 });
  console.log('[adaptive-smoke] model loaded; applying CPU throttle + watching fps...');

  const client = await page.target().createCDPSession();
  await client.send('Emulation.setCPUThrottlingRate', { rate: o.throttle });

  const start = Date.now();
  while (Date.now() - start < o.seconds * 1000) {
    await sleep(2000);
    const state = await page.evaluate(() => {
      const el = document.querySelector('.fps');
      return { fps: el ? el.textContent : '(no overlay)', pr: window.__viewer ? undefined : undefined };
    });
    console.log('  t+' + Math.round((Date.now() - start) / 1000) + 's  overlay=' + state.fps + '  tierSteps=' + tierLogs.length);
    if (tierLogs.length >= 3) break; // enough proof
  }

  await browser.close();

  console.log('\n[adaptive-smoke] tier-change log lines captured: ' + tierLogs.length);
  tierLogs.forEach((l) => console.log('  ' + l));
  if (tierLogs.length === 0) {
    console.error('[adaptive-smoke] NO downstep observed — fps stayed >=60 (raise --throttle or use a heavier asset).');
    process.exit(2);
  }
  console.log('[adaptive-smoke] PASS — adaptive quality degraded on sustained <60fps.');
}

main().catch((e) => { console.error('[adaptive-smoke] Fatal: ' + (e && e.stack ? e.stack : e)); process.exit(1); });
