#!/usr/bin/env python3
from pathlib import Path
import datetime as dt, hashlib, json, os, stat, subprocess

ROOT=Path('/data/video-pipeline/HaTramAudio/project/021-Ngay-Toi-Bi-Gach-Ten-Khoi-Gia-Pha')
PROJECT=ROOT.name;RUN='run-20260721T131911Z-ac5d64d1';CANON='bb80e97d9adcb0427ea3828449858445323db228cca38f37cdf0446fffefdd6f'
PROMPTS=ROOT/'work/artwork/image-prompts.json';SCRIPT=Path.home()/'.hermes/skills/content-creation/tao-anh/scripts/generate_image.py'
OUTPUTS={'intro':ROOT/'image/provider/intro-poster-provider.png','right':ROOT/'image/provider/right-panel-provider.png','left':ROOT/'image/provider/left-panel-provider.png'}

def now():return dt.datetime.now(dt.timezone.utc).isoformat().replace('+00:00','Z')
def sha(path):
 h=hashlib.sha256()
 with open(path,'rb') as f:
  while b:=f.read(8*1024*1024):h.update(b)
 return h.hexdigest()
def atomic(path,obj):
 path.parent.mkdir(parents=True,exist_ok=True);tmp=path.with_suffix(path.suffix+'.tmp');tmp.write_text(json.dumps(obj,ensure_ascii=False,indent=2)+'\n');tmp.replace(path)
def load_env():
 env=os.environ.copy();missing=[k for k in ('TAO_ANH_API_KEY','TAO_ANH_API_URL') if not env.get(k)]
 if missing:
  p=Path.home()/'.hermes/.env';assert p.exists() and stat.S_IMODE(p.stat().st_mode)==0o600
  for line in p.read_text().splitlines():
   if '=' in line and not line.lstrip().startswith('#'):
    k,v=line.split('=',1);env.setdefault(k.strip(),v.strip().strip('"').strip("'"))
 assert all(env.get(k) for k in ('TAO_ANH_API_KEY','TAO_ANH_API_URL'));return env
def guard(bundle):
 lock=json.loads((ROOT/'.ownership-lock.json').read_text());assert lock['project_id']==PROJECT and lock['run_id']==RUN and lock['owner']=='zoro' and lock['status']=='main_session_pipeline'
 assert sha(ROOT/'story/story-canon.txt')==CANON
 for rel,h in bundle['authority_sha256'].items():assert sha(ROOT/rel)==h,(rel,'authority drift')
def main():
 bundle=json.loads(PROMPTS.read_text());assert bundle['source_canon_sha256']==CANON and bundle['status']=='locked';env=load_env()
 for key in ('intro','right','left'):
  guard(bundle);out=OUTPUTS[key];receipt=ROOT/f'log/artwork-{key}.json';ph=hashlib.sha256(bundle['prompts'][key].encode()).hexdigest()
  if receipt.exists() and out.exists():
   old=json.loads(receipt.read_text())
   if old.get('status')=='completed' and old.get('artifact_sha256')==sha(out) and old.get('prompt_sha256')==ph:continue
  intent={'schema_version':1,'project_id':PROJECT,'run_id':RUN,'status':'creating','verified':False,'prompt_key':key,'prompt_sha256':ph,'source_canon_sha256':CANON,'output_path':str(out),'credential':'[REDACTED]','created_at':now()};atomic(receipt,intent)
  cp=subprocess.run(['python3',str(SCRIPT),'--prompt',bundle['prompts'][key],'--output',str(out),'--timeout','600'],env=env,capture_output=True,text=True)
  if cp.returncode!=0:
   intent.update({'status':'failed','failure':'provider command failed; stderr redacted','failed_at':now()});atomic(receipt,intent);raise RuntimeError(f'{key} provider failed')
  assert out.exists() and out.stat().st_size>0 and out.read_bytes()[:8]==b'\x89PNG\r\n\x1a\n'
  intent.update({'status':'completed','technical_verified':True,'verified':False,'awaiting_visual_qa':True,'artifact_sha256':sha(out),'size_bytes':out.stat().st_size,'completed_at':now()});atomic(receipt,intent)
 print(json.dumps({'status':'artwork_generated_awaiting_visual_qa','outputs':{k:{'path':str(v),'sha256':sha(v),'bytes':v.stat().st_size} for k,v in OUTPUTS.items()}},ensure_ascii=False))
if __name__=='__main__':main()
