#!/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-001-Han-Tin')
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, late Qin and early Western Han / Chu-Han contention China, sepia brown ochre charcoal ink wash, historically grounded handcrafted illustration, identity-locking face, full-body, costume and armor details, clean negative space.'
BASE_NEG = 'No modern objects, no fantasy armor, no Qing dynasty queue, no Tang/Song/Ming/Qing costume drift, no Japanese samurai, no European medieval armor, no text labels, no watermark, no vertical canvas, no square canvas.'
REQUIRED = {'Hàn Tín trẻ tuổi','Hàn Tín đại tướng','Lưu Bang','Tiêu Hà','Hạng Vũ','Lữ hậu','Binh sĩ Hán','Quân Sở'}
RECOMMENDED = {'Khoái Triệt'}

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' 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"{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()
