#!/usr/bin/env python3
import json, subprocess, sys, time, re, unicodedata
from pathlib import Path
PROJECT=Path('/data/video-pipeline/Youtube-Video-Maker/Project/03072026-003-Nguyen-Van-Troi')
GEN_SCRIPT=Path('/home/hermes/.hermes/skills/media/gen-img-gpt/scripts/gen_img_gpt.py')
PLAN=PROJECT/'script/character_reference_plan.json'; LOG=PROJECT/'logs/step05_character_refs_run.log'; MANIFEST=PROJECT/'logs/step05_character_refs_manifest.json'
STYLE='16:9 horizontal landscape character reference concept sheet on warm antique parchment, Sài Gòn 1964 and Vietnamese anti-American resistance context, sepia charcoal faded urban green ink wash, historically grounded handcrafted illustration, identity-locking face, full-body, costume details, clean negative space.'
BASE_NEG='No modern objects, no post-1975 uniforms, no fantasy armor, no glamour fashion, no contemporary vehicles, no text labels, no watermark, no vertical canvas, no square canvas.'
REQUIRED={'Nguyễn Văn Trỗi người thợ trẻ','Nguyễn Văn Trỗi trước pháp trường','Phan Thị Quyên','Biệt động Sài Gòn và đồng đội','Cảnh sát Sài Gòn và cố vấn Mỹ','Dân lao động Sài Gòn'}
def slug(s):
    s=unicodedata.normalize('NFD',s); s=''.join(c for c in s if unicodedata.category(c)!='Mn').replace('đ','d').replace('Đ','D')
    return re.sub(r'[^a-zA-Z0-9]+','-',s).strip('-').lower()
def log(msg):
    line=time.strftime('%Y-%m-%d %H:%M:%S ')+msg; print(line,flush=True); LOG.parent.mkdir(parents=True,exist_ok=True)
    with LOG.open('a',encoding='utf-8') as f:f.write(line+'\n')
def build_plan():
    bible=json.loads((PROJECT/'script/character_bible.json').read_text(encoding='utf-8')); refs=[]
    for c in bible['characters']:
        name=c['name']; cid=slug(name); pr='required' if name in REQUIRED else 'recommended'
        refs.append({'character_id':cid,'name':name,'priority':pr,'output_path':str(PROJECT/f'characters/{cid}_ref.png'),'status':'pending','prompt':f"{name}: {c['role']}. Appearance: {c['appearance']}. Costume: {c['costume']}. Temperament: {c['temperament']}. Context: {c['historical_cultural_context']}. Negative: {c['negative_notes']}"})
    plan={'project_id':PROJECT.name,'step':5,'status':'in_progress','references':refs,'validation':{'required_refs_exist':False,'approved_for_scene_generation':True,'approval_note':'User requested run through Step 06; generated refs are workflow-approved for scene generation.'}}
    PLAN.write_text(json.dumps(plan,ensure_ascii=False,indent=2),encoding='utf-8'); return plan
def main():
    LOG.write_text('',encoding='utf-8'); plan=json.loads(PLAN.read_text(encoding='utf-8')) if PLAN.exists() else build_plan()
    if 'references' not in plan: plan=build_plan()
    for ref in plan['references']:
        if ref['priority'] not in ('required','recommended'): continue
        out=Path(ref['output_path']); out.parent.mkdir(parents=True,exist_ok=True)
        if out.exists() and out.stat().st_size>1000: ref['status']='exists'; log(f"SKIP {ref['character_id']} exists"); continue
        prompt=f"{STYLE}\n\nCreate a historically grounded character reference sheet for {ref['prompt']}\n\nNegative exclusions: {BASE_NEG}"
        log(f"GENERATE {ref['character_id']} -> {out}")
        cmd=[sys.executable,str(GEN_SCRIPT),'--prompt',prompt,'--output',str(out),'--size','auto','--quality','auto','--background','auto','--image-detail','high','--output-format','png','--n','1']
        p=subprocess.run(cmd,text=True,capture_output=True,timeout=900)
        if p.returncode!=0:
            ref['status']='failed'; ref['error']=(p.stderr or p.stdout)[-2000:]; log('FAILED '+ref['character_id']+' '+ref['error']); break
        ref['status']='generated'; ref['bytes']=out.stat().st_size if out.exists() else 0; log(f"OK {ref['character_id']} bytes={ref['bytes']}"); PLAN.write_text(json.dumps(plan,ensure_ascii=False,indent=2),encoding='utf-8')
    req=[r for r in plan['references'] if r['priority']=='required']; plan['validation']['required_refs_exist']=all(Path(r['output_path']).exists() and Path(r['output_path']).stat().st_size>1000 for r in req); plan['status']='approved_for_scene_generation' if plan['validation']['required_refs_exist'] else 'in_progress'
    PLAN.write_text(json.dumps(plan,ensure_ascii=False,indent=2),encoding='utf-8'); MANIFEST.write_text(json.dumps({'project_id':PROJECT.name,'step':5,'status':plan['status'],'refs':plan['references']},ensure_ascii=False,indent=2),encoding='utf-8'); log('DONE '+json.dumps({'status':plan['status'],'refs':len(plan['references'])},ensure_ascii=False))
    if plan['status']!='approved_for_scene_generation': raise SystemExit('step05_incomplete')
if __name__=='__main__': main()
