#!/usr/bin/env python3
import json, subprocess, sys, time, re, unicodedata
from pathlib import Path
PROJECT = Path('/data/video-pipeline/Youtube-Video-Maker/Project/001-La-Van-Cau')
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 American Vietnam War gear, 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, Vietnamese First Indochina War 1950 Cao Bang and Dong Khe, 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 = {'La Văn Cầu người lính trẻ','La Văn Cầu ôm bộc phá','Tổ bộc phá Trung đoàn 174'}
RECOMMENDED = {'Đồng đội và dân công Cao Bằng','Quân Pháp tại Đông Khê'}
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['name']='Generate Character References'; 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 Viet Minh, Cao Bang mountain people, French colonial Indochina War 1950 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()
