import { chromium } from 'playwright';
import { spawn, spawnSync } from 'node:child_process';
import { once } from 'node:events';
import { mkdir, writeFile, rename, unlink } from 'node:fs/promises';
import { serve } from './serve.mjs';
import { ADS, DURATION, FPS, getFormat } from '../src/config.js';
const names=process.argv.slice(2).length?process.argv.slice(2):Object.keys(ADS);
if(names.some(key=>!ADS[key]))throw new Error('Use electro, lighting, lifts or side');
for(const bin of ['ffmpeg','ffprobe'])if(spawnSync(bin,['-version']).status!==0)throw new Error(`Install ${bin}: sudo apt install ffmpeg`);
await mkdir('output',{recursive:true});await mkdir('qa',{recursive:true});
const {server,url}=await serve();let browser;
try{
 browser=await chromium.launch({headless:true,args:['--no-sandbox','--disable-dev-shm-usage'],...(process.env.CHROMIUM_PATH?{executablePath:process.env.CHROMIUM_PATH}:{})});
 const page=await browser.newPage({viewport:{width:320,height:512},deviceScaleFactor:2});
 page.on('pageerror',error=>{throw error;});
 await page.goto(`${url}/render.html`);await page.waitForFunction(()=>window.ready);
 for(const ad of names){
  const {width,height,safeX,safeY}=getFormat(ad);
  const dest=`output/${ADS[ad].file}`,temp=dest.replace('.mp4','.partial.mp4');
  const encoder=spawn('ffmpeg',['-hide_banner','-loglevel','error','-y','-f','image2pipe','-framerate',String(FPS),'-vcodec','png','-i','pipe:0','-vf',`scale=${width}:${height}:flags=lanczos,setsar=1`,'-an','-c:v','libx264','-preset','slow','-crf','16','-profile:v','baseline','-level:v','3.0','-pix_fmt','yuv420p','-r',String(FPS),'-frames:v',String(DURATION*FPS),'-threads','2','-color_primaries','bt709','-color_trc','bt709','-colorspace','bt709','-movflags','+faststart',temp],{stdio:['pipe','inherit','pipe']});
  let error='';encoder.stderr.on('data',d=>error+=d);const done=once(encoder,'close');encoder.stdin.on('error',()=>{});
  let violations=[];
  console.log(`Rendering ${ad}: 450 frames at ${width*2}×${height*2} → ${width}×${height}`);
  try{
   for(let frame=0;frame<DURATION*FPS;frame++){
    const data=await page.evaluate(({ad,t,width,height,safeX,safeY})=>{const bounds=window.renderFrame(ad,t);return{image:document.querySelector('canvas').toDataURL('image/png').split(',')[1],violations:bounds.filter(b=>b.left<safeX-.5||b.right>width-safeX+.5||b.top<safeY-.5||b.bottom>height-safeY+.5)};},{ad,t:frame/FPS,width,height,safeX,safeY});
    if(data.violations.length)violations.push({frame,violations:data.violations});
    const buffer=Buffer.from(data.image,'base64');if(!encoder.stdin.write(buffer))await once(encoder.stdin,'drain');
    if(frame===120)await writeFile(`output/${ad}-poster.png`,buffer);
    if(frame%90===0)console.log(`${ad}: ${frame}/450`);
   }
   encoder.stdin.end();const[code]=await done;if(code!==0)throw new Error(error);
   await rename(temp,dest);
  }catch(error){encoder.kill('SIGTERM');await unlink(temp).catch(()=>{});throw error;}
  const probe=spawnSync('ffprobe',['-v','error','-count_frames','-show_streams','-show_format','-of','json',dest],{encoding:'utf8'});
  if(probe.status!==0)throw new Error(probe.stderr);const metadata=JSON.parse(probe.stdout),video=metadata.streams[0];
  if(metadata.streams.length!==1||video.codec_name!=='h264'||video.width!==width||video.height!==height||video.r_frame_rate!=='30/1'||video.pix_fmt!=='yuv420p'||Number(video.nb_read_frames)!==450||Number(metadata.format.duration)!==15)throw new Error(`Invalid output: ${dest}`);
  await writeFile(`qa/${ad}-metadata.json`,JSON.stringify(metadata,null,2));await writeFile(`qa/${ad}-safe-zone.json`,JSON.stringify(violations,null,2));
  if(violations.length)throw new Error(`${ad}: text exceeds safe zone in ${violations.length} frames; see qa/${ad}-safe-zone.json`);
  console.log(`Verified ${dest}: H.264, ${width}×${height}, 30fps, 15s, 450 frames, no audio.`);
 }
}finally{await browser?.close();await new Promise(resolve=>server.close(resolve));}
