#!/usr/bin/env python3
from pathlib import Path
import hashlib,json,subprocess,time,urllib.error,urllib.request,wave
P=Path(__file__).resolve().parents[1];ROOT=Path('/data/video-pipeline').resolve();BASE='http://192.168.1.104:8021'
def safe(x):
 p=Path(x).resolve();p.relative_to(ROOT);assert p.exists() or p.parent.exists();return str(p)
def wavdur(x):
 with wave.open(str(x),'rb') as w:return w.getnframes()/w.getframerate()
def sha(x):return hashlib.sha256(Path(x).read_bytes()).hexdigest()
def probe(f):return json.loads(subprocess.check_output(['ffprobe','-v','error','-show_streams','-show_format','-of','json',str(f)]))
def valid_video(f):
 try:
  q=probe(f);v=next(x for x in q['streams'] if x['codec_type']=='video');return (v['width'],v['height'],v['codec_name'],v['r_frame_rate'])==(1920,1080,'h264','30/1') and any(x['codec_type']=='audio' for x in q['streams']) and Path(f).stat().st_size>10000
 except:return False
def post(payload,name):
 (P/f'logs/render_{name}_request.json').write_text(json.dumps(payload,indent=2)+'\n');req=urllib.request.Request(BASE+'/stickman-render-gpu',data=json.dumps(payload).encode(),headers={'Content-Type':'application/json'},method='POST')
 for a in range(12):
  try:
   with urllib.request.urlopen(req,timeout=3600) as r:d=json.load(r)
   if d.get('status')=='error' or d.get('detail'):raise RuntimeError(d)
   (P/f'logs/render_{name}_response.json').write_text(json.dumps(d,indent=2)+'\n');return d
  except urllib.error.HTTPError as e:
   body=e.read().decode(errors='replace');(P/f'logs/render_{name}_http_error.json').write_text(json.dumps({'code':e.code,'body':body[:4000]})+'\n')
   if e.code==409:time.sleep(min(60,5*(a+1)));continue
   raise
 raise RuntimeError('gpu lock retries exhausted')
def main():
 m=json.loads((P/'asr/timeline.json').read_text());jobs=[('intro',[{'image_path':safe(P/'images/intro_poster.png'),'duration':wavdur(P/'audio/intro_padded.wav')}],P/'audio/intro_padded.wav',P/'video/intro.mp4'),('outro',[{'image_path':safe(P/'images/outro_poster.png'),'duration':wavdur(P/'audio/outro.wav')}],P/'audio/outro.wav',P/'video/outro.mp4'),('main',[{'image_path':safe(P/f'images/scenes/scene_{s["id"]:03d}.png'),'duration':s['duration']} for s in m['scenes']],P/'audio/full_narration.wav',P/'video/output/main.mp4')]
 for name,scenes,audio,out in jobs:
  if valid_video(out):print(name,'existing');continue
  h=json.load(urllib.request.urlopen(BASE+'/health',timeout=30));assert h.get('status')=='ok' and h.get('nvenc_available') is True and h.get('gpu',{}).get('available') is True and h.get('encoder')=='h264_nvenc' and '/stickman-render-gpu' in h.get('endpoints',[]),h
  payload={'job_id':f'030-{name}','scenes':scenes,'audio_path':safe(audio),'output_path':str(out.resolve()),'width':1920,'height':1080,'fps':30,'crf':20,'transition':'cut','timeline_start_sec':0,'timeline_end_sec':sum(x['duration'] for x in scenes),'burn_subtitles':False,'motion':False,'input_hashes':{'audio':sha(audio),'images':[sha(x['image_path']) for x in scenes]}}
  d=post(payload,name);assert d.get('service')=='dedicated-gpu-story-render' and d.get('encoder')=='h264_nvenc',d;assert valid_video(out);print(name,'PASS')
 print('GPU_RENDER_GATE PASS')
if __name__=='__main__':main()
