#!/usr/bin/env python3
from pathlib import Path
import datetime as dt,hashlib,json,subprocess,time,urllib.request
ROOT=Path('/data/video-pipeline/HaTramAudio/project/021-Ngay-Toi-Bi-Gach-Ten-Khoi-Gia-Pha');RUN='run-20260721T131911Z-ac5d64d1';BASE='http://192.168.1.104:8023'
INTRO=ROOT/'output/intro/intro.mp4';FOOTAGE=ROOT/'output/footage/footage.mp4';OUT=ROOT/'output/final.mp4';INTENT=ROOT/'log/final-intent.json';RECEIPT=ROOT/'log/final-render.json'
IH='d0b43671b1ed06396b8a3e61b462d7d885a8ae1eeeab5112eb70eb0ef812245b';FH='7fb56d54eb2ebb9a3efda7989e2cd975fd810467d28152aa3fc5ab7a1502d09f'
def now():return dt.datetime.now(dt.timezone.utc).isoformat().replace('+00:00','Z')
def sha(p):
 h=hashlib.sha256()
 with open(p,'rb') as f:
  while b:=f.read(8*1024*1024):h.update(b)
 return h.hexdigest()
def atomic(p,o):
 t=p.with_suffix(p.suffix+'.tmp');t.write_text(json.dumps(o,ensure_ascii=False,indent=2)+'\n');t.replace(p)
def get(path):
 with urllib.request.urlopen(BASE+path,timeout=30) as r:return json.loads(r.read())
def main():
 lock=json.loads((ROOT/'.ownership-lock.json').read_text());assert lock['run_id']==RUN and lock['owner']=='zoro' and lock['status']=='main_session_pipeline';assert sha(INTRO)==IH and sha(FOOTAGE)==FH;assert json.loads((ROOT/'log/intro-render.json').read_text())['verified'];assert json.loads((ROOT/'log/footage-render.json').read_text())['verified']
 health=get('/health');assert health['status']=='ok' and health['h264_nvenc'] is True
 if INTENT.exists():intent=json.loads(INTENT.read_text());jid=intent['job_id'];job=get('/v1/huyenan-render-final/jobs/'+jid)
 else:
  listing=get('/v1/huyenan-render-final/jobs');jobs=listing.get('jobs',[]) if isinstance(listing,dict) else listing;assert not [x for x in jobs if isinstance(x,dict) and x.get('status') in ('queued','running')]
  payload={'intro_video_path':str(INTRO),'footage_video_path':str(FOOTAGE),'output_video_path':str(OUT),'fps':30,'width':1920,'height':1080,'video_encoder':'h264_nvenc','preset':'p4','cq':21};assert 'main_audio_path' not in payload
  intent={'schema_version':1,'project_id':ROOT.name,'run_id':RUN,'status':'creating','intro_sha256':IH,'footage_sha256':FH,'payload':payload,'created_at':now()};atomic(INTENT,intent);req=urllib.request.Request(BASE+'/v1/huyenan-render-final/jobs',data=json.dumps(payload).encode(),headers={'Content-Type':'application/json'},method='POST')
  with urllib.request.urlopen(req,timeout=60) as r:job=json.loads(r.read())
  jid=job.get('job_id') or job.get('id');assert jid;intent.update({'status':'submitted','job_id':jid,'submitted_at':now()});atomic(INTENT,intent)
 while job.get('status') in ('queued','running'):time.sleep(20);job=get('/v1/huyenan-render-final/jobs/'+jid)
 if job.get('status')!='completed':atomic(RECEIPT,{'schema_version':1,'project_id':ROOT.name,'run_id':RUN,'status':'failed','verified':False,'job_id':jid,'endpoint_response':job,'failed_at':now()});raise RuntimeError(str(job.get('status')))
 assert job.get('verification',{}).get('verified') is True and OUT.exists();h=sha(OUT);probe=json.loads(subprocess.run(['ffprobe','-v','error','-show_entries','format=duration,size:stream=index,codec_type,codec_name,width,height,r_frame_rate,sample_rate,channels','-of','json',str(OUT)],capture_output=True,text=True,check=True).stdout)
 rec={'schema_version':1,'project_id':ROOT.name,'run_id':RUN,'status':'awaiting_visual_qa','technical_verified':True,'verified':False,'intro_sha256':IH,'footage_sha256':FH,'job_id':jid,'output_path':str(OUT),'output_sha256':h,'output_size_bytes':OUT.stat().st_size,'probe':probe,'main_audio_path_sent':False,'endpoint_response':job,'completed_at':now()};atomic(RECEIPT,rec);print(json.dumps({'status':'awaiting_visual_qa','job_id':jid,'bytes':OUT.stat().st_size,'sha256':h},ensure_ascii=False))
if __name__=='__main__':main()
