#!/usr/bin/env python3
from pathlib import Path
import os,json,hashlib,requests,datetime
P='gacmai_20260718_075153';R=Path('/data/video-pipeline/GacMaiAudio/project')/P;A=R/'artifacts'
def env(path):
 for line in Path(path).read_text(errors='ignore').splitlines():
  line=line.strip()
  if line and not line.startswith('#') and '=' in line:
   k,v=line.split('=',1);os.environ.setdefault(k.strip(),v.strip().strip('"\''))
def sha(p):return hashlib.sha256(Path(p).read_bytes()).hexdigest()
env('/opt/OpenMontage/.env')
assets={'intro':R/'assets/images/intro_campaign_rev5.png','left':R/'assets/images/left_campaign_rev1.png','right':R/'assets/images/right_campaign_rev1.png','composite':R/'assets/images/main_frame_campaign_rev1.png','audio':R/'assets/audio/narration_final.wav'}
shas={k:sha(v) for k,v in assets.items()}
accept={'status':'passed','project_id':P,'visual_contract_sha256':sha(A/'visual_campaign_contract.json'),'assets':{k:{'path':str(v),'sha256':shas[k]} for k,v in assets.items() if k!='audio'},'source_audit':'passed','final_composite_audit':'passed','geometry':{'canvas':[1920,1080],'panels':[600,720,600],'center_rgb':'#00FF00','green_center_pixels':777600,'green_outside_pixels':0},'accepted_at':datetime.datetime.now(datetime.timezone.utc).isoformat()}
(A/'visual_campaign_acceptance_rev1.json').write_text(json.dumps(accept,ensure_ascii=False,indent=2)+'\n')
auth={'status':'authorized','project_id':P,'campaign_acceptance_sha256':sha(A/'visual_campaign_acceptance_rev1.json'),'visual_contract_sha256':accept['visual_contract_sha256'],'story_sha256':'8a2d835732a26e289ab1f918def3092f607f4abe2a3ab32cd9f06cbed9ae3c66','audio_sha256':shas['audio'],'input_sha256':shas,'output':str(R/'render/final_campaign_rev1.mp4'),'authorized_at':accept['accepted_at']};(A/'visual_render_authorization.json').write_text(json.dumps(auth,ensure_ascii=False,indent=2)+'\n')
# Assert files still match authorization immediately before side effect.
for k,p in assets.items():assert sha(p)==auth['input_sha256'][k]
base='http://192.168.1.104:8020';key=next((os.environ.get(k) for k in ('GACMAI_RENDER_API_KEY','GPU_RENDER_API_KEY','RENDER_API_KEY','OPENMONTAGE_RENDER_API_KEY') if os.environ.get(k)),None)
if not key:raise SystemExit('render API key unavailable')
h={'X-API-Key':key};health=requests.get(base+'/health',headers=h,timeout=20);health.raise_for_status();hd=health.json();assert hd.get('status')=='ok' and hd.get('h264_nvenc') is True
body={'frame':str(assets['composite']),'intro_poster':str(assets['intro']),'intro_visual_end':6.56862,'audio':str(assets['audio']),'footage_dir':'/data/video-pipeline/GacMaiAudio/footage','output':auth['output'],'seed':20260718,'pattern':'gacmai-*.mp4','fps':24}
r=requests.post(base+'/v1/jobs',headers={**h,'Content-Type':'application/json'},json=body,timeout=30);r.raise_for_status();d=r.json();jid=d.get('job_id') or d.get('id');assert jid
rec={'status':'submitted','job_id':jid,'status_url':base+'/v1/jobs/'+jid,'request':body,'authorization_sha256':sha(A/'visual_render_authorization.json'),'health':hd,'expected':{'renderer':'h264_nvenc','source_audio_discarded':True,'horizontal_mirror':'hflip'}};(A/'gpu_render_submission_rev1.json').write_text(json.dumps(rec,ensure_ascii=False,indent=2)+'\n');print(json.dumps({'status':'submitted','job_id':jid,'status_url':rec['status_url']}))
