#!/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:8024';IN=ROOT/'output/final.mp4';OUT=ROOT/'output/final-upload.mp4';INTENT=ROOT/'log/transcode-intent.json';RECEIPT=ROOT/'log/transcode-upload.json';MASTER='2b331a8b7e64352c866ede0215a52f39b344cbc460c3036d967ad7013811a1c0';CANON='bb80e97d9adcb0427ea3828449858445323db228cca38f37cdf0446fffefdd6f'
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():
 assert sha(IN)==MASTER and json.loads((ROOT/'log/final-render.json').read_text())['verified'];h=get('/health');assert h['status']=='ok' and h['h264_nvenc'] is True
 if INTENT.exists():intent=json.loads(INTENT.read_text());jid=intent['job_id'];job=get('/v1/huyenan-transcode-upload/jobs/'+jid)
 else:
  listing=get('/v1/huyenan-transcode-upload/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={'input_video_path':str(IN),'output_video_path':str(OUT),'target_output_bytes':800000000,'max_output_bytes':1000000000,'width':1920,'height':1080,'fps':30,'audio_bitrate_kbps':96,'overwrite':False};intent={'schema_version':1,'project_id':ROOT.name,'run_id':RUN,'status':'creating','source_canon_sha256':CANON,'master_sha256':MASTER,'payload':payload,'created_at':now()};atomic(INTENT,intent);req=urllib.request.Request(BASE+'/v1/huyenan-transcode-upload/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-transcode-upload/jobs/'+jid)
 if job.get('status')!='completed':raise RuntimeError(str(job.get('status')))
 ver=job.get('verification',{});assert ver.get('verified') is True and ver.get('under_one_gb') is True and OUT.exists() and OUT.stat().st_size<1_000_000_000
 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':'completed','verified':True,'source_canon_sha256':CANON,'master_sha256':MASTER,'job_id':jid,'output_path':str(OUT),'output_sha256':sha(OUT),'output_size_bytes':OUT.stat().st_size,'under_one_gb':True,'probe':probe,'endpoint_response':job,'completed_at':now()};atomic(RECEIPT,rec);print(json.dumps({'status':'completed','verified':True,'job_id':jid,'bytes':OUT.stat().st_size,'sha256':rec['output_sha256']},ensure_ascii=False))
if __name__=='__main__':main()
