#!/usr/bin/env python3
import json, subprocess, sys, time, re, unicodedata
from pathlib import Path
PROJECT = Path('/data/video-pipeline/Youtube-Video-Maker/Project/003-Nha-Han-202-TCN-220')
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 queue hairstyle, no Ming robe, no Japanese samurai look, no European medieval armor, 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, Han dynasty China from Western Han to Eastern Han, sepia brown ochre charcoal ink wash, historically grounded ancient Chinese costume and armor, controlled face/full-body/costume details for identity locking, clean negative space.'
REQUIRED = {'Lưu Bang / Hán Cao Tổ','Hạng Vũ','Lữ hậu','Hán Vũ Đế / Lưu Triệt','Vệ Thanh và Hoắc Khứ Bệnh','Trương Khiên','Tư Mã Thiên','Vương Mãng','Lưu Tú / Hán Quang Vũ Đế','Trương Giác và Khăn Vàng','Tào Tháo, Lưu Bị, Tôn Quyền'}
RECOMMENDED = set()
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':False}}
    PLAN.write_text(json.dumps(plan,ensure_ascii=False,indent=2),encoding='utf-8')
    return plan
def update_check(status):
    check=json.loads((PROJECT/'checklist_19_steps.json').read_text(encoding='utf-8'))
    for s in check['steps']:
        if s['step']==5:
            s['status']=status; s['completed_at']=time.strftime('%Y-%m-%dT%H:%M:%S') if status=='completed' else None
    (PROJECT/'checklist_19_steps.json').write_text(json.dumps(check,ensure_ascii=False,indent=2),encoding='utf-8')
    (PROJECT/'checklist_19_steps.md').write_text('# Checklist 19 Steps\n\n'+'\n'.join(f"- [{'x' if x['status']=='completed' else ' '}] Step {x['step']:02d}: {x['name']} - {x['status']}" for x in check['steps'])+'\n',encoding='utf-8')
def main():
    LOG.write_text('',encoding='utf-8')
    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/material details, historically grounded Han dynasty visual culture where relevant.\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=1200)
        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['validation']['approved_for_scene_generation']=plan['validation']['required_refs_exist']
    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')
    update_check('completed' if plan['status']=='approved_for_scene_generation' else 'pending')
    log('DONE '+json.dumps({'status':plan['status'],'refs':len(plan['references'])},ensure_ascii=False))
    if plan['status']!='approved_for_scene_generation': raise SystemExit(1)
if __name__=='__main__': main()
