/*
 * sabr-client-test.mjs — milestone 3 gate. Drives the dependency-free
 * sabr-client.mjs (the worker port) against a harvested capture and checks it
 * drains video+audio to the exact contentLength — i.e. the hand-rolled
 * proto+UMP+loop reproduces googlevideo's sabr-drain-capture result with ZERO
 * googlevideo code in the path.
 *
 *   node tools/sabr-client-test.mjs [tools/captured.json] [--id=VIDEOID] [--video=itag] [--audio=itag]
 */
import { readFile } from 'node:fs/promises';
import { driveSabr } from './sabr-client.mjs';

const flags = Object.fromEntries(process.argv.slice(2).filter(a => a.startsWith('--')).map(a => { const [k, v] = a.replace(/^--/, '').split('='); return [k, v ?? true]; }));
const path = process.argv.slice(2).find(a => !a.startsWith('--')) || new URL('./captured.json', import.meta.url).pathname;
const ID = flags.id || 'BRfjeH366EY';
const WANT_VIDEO = flags.video ? Number(flags.video) : 134;
const WANT_AUDIO = flags.audio ? Number(flags.audio) : 140;

const cap = JSON.parse(await readFile(path, 'utf8'));
const body = Uint8Array.from(atob(cap.bodyB64), c => c.charCodeAt(0));

// pull ustreamerConfig (field 5) out of the captured request body
const readVarint = (b, p) => { let r = 0, s = 0, x; do { x = b[p++]; r += (x & 0x7f) * Math.pow(2, s); s += 7; } while (x & 0x80); return [r, p]; };
function field(buf, target) { let pos = 0; while (pos < buf.length) { let tag; [tag, pos] = readVarint(buf, pos); const f = tag >> 3, wt = tag & 7; if (wt === 2) { let len; [len, pos] = readVarint(buf, pos); if (f === target) return buf.subarray(pos, pos + len); pos += len; } else if (wt === 0)[, pos] = readVarint(buf, pos); else if (wt === 1) pos += 8; else if (wt === 5) pos += 4; else return null; } return null; }
const ustreamer = field(body, 5);

// iOS player POST → format metadata (lastModified + contentLength) for the wanted itags
const visitor = decodeURIComponent(cap.visitor);
async function iosFormats() {
  const b = { videoId: ID, racyCheckOk: true, contentCheckOk: true, context: { client: { clientName: 'iOS', clientVersion: '20.11.6', deviceMake: 'Apple', deviceModel: 'iPhone10,4', osName: 'iOS', osVersion: '16.7.7.20H330', hl: 'en', gl: 'US', visitorData: visitor }, user: {}, request: { useSsl: true } } };
  const r = await fetch('https://www.youtube.com/youtubei/v1/player?prettyPrint=false', { method: 'POST', headers: { 'Content-Type': 'application/json', 'X-Youtube-Client-Name': '5', 'X-Youtube-Client-Version': '20.11.6', 'X-Goog-Visitor-Id': visitor, 'User-Agent': 'com.google.ios.youtube/20.11.6 (iPhone10,4; U; CPU iOS 16_7_7 like Mac OS X)' }, body: JSON.stringify(b) });
  return (await r.json()).streamingData?.adaptiveFormats || [];
}
const adaptive = await iosFormats();
const pick = (itag) => { const f = adaptive.find(x => x.itag === itag); return f && { itag, lastModified: String(f.lastModifiedTime || f.lastModified), clen: Number(f.contentLength) }; };
const v = pick(WANT_VIDEO), a = pick(WANT_AUDIO);
if (!v || !a) { console.error(`itag ${WANT_VIDEO}/${WANT_AUDIO} not found in player response`); process.exit(1); }

const headers = { 'Referer': 'https://www.youtube.com/', 'Origin': 'https://www.youtube.com', 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/130.0.0.0 Safari/537.36' };

console.log(`\n=== sabr-client-test (hand-rolled, NO googlevideo)  ${ID}  v=${v.itag}(${v.clen}) a=${a.itag}(${a.clen}) ===`);
let last = 0;
try {
  const { video, audio } = await driveSabr({
    serverAbrStreamingUrl: cap.url,
    ustreamerConfig: ustreamer,
    poToken: cap.pot,
    clientInfo: { clientName: 1, clientVersion: '2.20260529.01.00', osName: 'Windows', osVersion: '10.0' },
    video: { itag: v.itag, lastModified: v.lastModified },
    audio: { itag: a.itag, lastModified: a.lastModified },
    fetchFn: (url, init) => fetch(url, { ...init, headers: { ...(init.headers || {}), ...headers } }),
    onProgress: (t) => { if (t - last > 1_000_000) { last = t; process.stdout.write(`\r  draining… ${t} bytes`); } }
  });
  console.log('\n\n=== RESULT ===');
  console.log(`video itag ${v.itag}: ${video} / ${v.clen}  ${video === v.clen ? '✓ EXACT' : (video >= v.clen * 0.99 ? '✓ full' : '✗ SHORT')}`);
  console.log(`audio itag ${a.itag}: ${audio} / ${a.clen}  ${audio === a.clen ? '✓ EXACT' : (audio >= a.clen * 0.99 ? '✓ full' : '✗ SHORT')}`);
  const ok = video === v.clen && audio === a.clen;
  console.log(`\nHAND-ROLLED SABR CLIENT: ${ok ? '✓✓ EXACT-BYTE DRAIN — matches googlevideo, ready for worker port' : '✗ mismatch'}\n`);
  process.exitCode = ok ? 0 : 1;
} catch (e) {
  console.log(`\n\n*** driveSabr threw: ${e.message} ***\n`);
  process.exitCode = 1;
}
