#!/usr/bin/env python3
import json, subprocess, sys, time, re, unicodedata
from pathlib import Path
PROJECT = Path('/data/video-pipeline/Youtube-Video-Maker/Project/29062026-001-Nha-Mac')
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'
BASE_NEG = 'No modern objects, no fantasy armor, no Qing dynasty queue, no Chinese opera costume, no European medieval armor, no Japanese samurai look, no text labels, no watermark, no vertical portrait canvas, no square canvas.'
STYLE = '16:9 horizontal landscape character reference concept sheet on warm antique parchment, 16th-century Dai Viet Mac dynasty / Nam Bac Trieu Vietnam, sepia brown ochre charcoal ink wash, handcrafted Vietnamese co phong historical feeling, controlled face/full-body/costume details for identity locking, clean negative space, historically grounded.'
REQUIRED = {'Mạc Đăng Dung','Mạc Đăng Doanh','Mạc Mậu Hợp','Nguyễn Bỉnh Khiêm / Bạch Vân cư sĩ','Lê Trung hưng / Lê Trang Tông','Nguyễn Kim và Trịnh Kiểm','Trịnh Tùng và quân Lê-Trịnh','Dân chúng Nam-Bắc triều','Quân Mạc / Bắc triều'}
RECOMMENDED = {'Sĩ phu và quan lại Đại Việt','Nhà Minh sứ thần và biên giới'}
def slug(s):
    s=unicodedata.normalize('NFD',s); s=''.join(c for c in s if unicodedata.category(c)!='Mn'); s=s.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' if name in RECOMMENDED else 'optional'
        refs.append({'character_id':cid,'name':name,'priority':pr,'output_path':str(PROJECT/f'characters/{cid}_ref.png'),'status':'pending','prompt':f"{c['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 character reference sheet for {ref['prompt']}. Include consistent identity, face close-up, full-body view, costume/armor/material details, historically grounded 16th-century Vietnamese Dai Viet visual culture.\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']}")
    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'],'plan_path':str(PLAN),'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()
