#!/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'; JID='3506858b713440a297ee623f603f495e'
BASE='http://192.168.1.104:8022'; OUT=ROOT/'output/footage/footage.mp4'; RECEIPT=ROOT/'log/footage-render.json'
CANON='bb80e97d9adcb0427ea3828449858445323db228cca38f37cdf0446fffefdd6f'; AUDIO='f39e3db2b844dd4740e2509e46787a3aafb42110df26b1e9c0bceac675e3ad08'; LAYOUT='415639e1d60ad353b7af2618c14a73a1c949ec18e40a5771425a6d491d770e76'
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 get():
 with urllib.request.urlopen(BASE+'/v1/footage-render-huyenan/jobs/'+JID,timeout=30) as r:return json.loads(r.read())
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 main():
 intent=json.loads((ROOT/'log/footage-intent.json').read_text());lock=json.loads((ROOT/'.ownership-lock.json').read_text())
 assert intent['job_id']==JID and intent['run_id']==RUN and intent['audio_sha256']==AUDIO and intent['layout_sha256']==LAYOUT
 assert lock['run_id']==RUN and lock['owner']=='zoro' and lock['status']=='main_session_pipeline'
 assert sha(ROOT/'story/story-canon.txt')==CANON and sha(ROOT/'audio/story-full.wav')==AUDIO and sha(ROOT/'image/normalized/layout-1920x1080.png')==LAYOUT
 job=get()
 while job.get('status') in ('queued','running'):
  time.sleep(30);job=get()
 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('terminal '+str(job.get('status')))
 assert job.get('id')==JID and job.get('verification',{}).get('verified') is True and OUT.exists()
 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)
 receipt={'schema_version':1,'project_id':ROOT.name,'run_id':RUN,'status':'endpoint_completed_pending_independent_qa','verified':False,'source_canon_sha256':CANON,'audio_sha256':AUDIO,'layout_sha256':LAYOUT,'job_id':JID,'output_path':str(OUT),'output_sha256':sha(OUT),'output_size_bytes':OUT.stat().st_size,'hash_method':'sha256_stream_8MiB','horizontal_mirror':'hflip','source_audio_discarded':True,'probe':probe,'endpoint_response':job,'completed_at':now()};atomic(RECEIPT,receipt)
 print(json.dumps({'status':receipt['status'],'job_id':JID,'bytes':receipt['output_size_bytes'],'sha256':receipt['output_sha256']},ensure_ascii=False))
if __name__=='__main__':main()
