#!/usr/bin/env python3
import json
import os
import re
import subprocess
import sys
from concurrent.futures import ThreadPoolExecutor, as_completed
from datetime import datetime
from pathlib import Path

PROJECT = Path('/data/video-pipeline/Youtube-Video-Maker/Project/31052026-001-Nguyen-Hue-Quang-Trung')
SCENES_PATH = PROJECT / 'script/scenes.json'
REF_PLAN_PATH = PROJECT / 'script/character_reference_plan.json'
GEN_SCRIPT = Path('/home/hermes/.hermes/skills/media/gen-img-gpt/scripts/gen_img_gpt.py')
MANIFEST_PATH = PROJECT / 'logs/step06_first50_images_manifest.json'
RUN_LOG = PROJECT / 'logs/step06_first50_images_run.log'
LIMIT = 50
WORKERS = 7

STYLE = """[VISUAL STYLE]
Vietnamese historical ink-wash storytelling illustration, 16:9 horizontal composition/canvas, centered irregular ink-wash window on warm antique cream paper. The painted image should occupy only about 65-70% of the page, leaving 30-35% negative space of antique paper. Do not fill the whole frame. Balanced breathing room, light page composition, handcrafted historical mood, soft brown-black ink, transparent watercolor wash, muted earthy palette.

[HISTORICAL GROUNDING]
Late 18th-century Dai Viet during the Tay Son uprising and the Quang Trung era; Binh Dinh highlands, Phu Xuan, Gia Dinh river country, Bac Ha and Thang Long; Vietnamese villages, royal courts, river fleets, war elephants, muskets, spears, drums, banners, bamboo, wood, earthworks, winter campaign atmosphere. Keep Vietnamese Tay Son/Le/Nguyen clothing distinct from Qing and Siamese troops. Avoid fantasy drift, European drift, and wrong cultural costumes.
"""
NEG = """[NEGATIVE EXCLUSIONS]
Not a character sheet, not a turnaround sheet, not a concept art board, not multiple views, not a lineup, not floating costume parts, not isolated armor pieces, not a design sheet, not a model sheet, not a reference layout, not modern objects, not watermark, not logo, not text labels, not poster typography, not edge-to-edge full-frame illustration, not glossy 3D, not game key art.
"""

KEYWORDS = [
    ('nguyen-hue_ref.png', ['Nguyễn Huệ','Quang Trung','ông ','vua Quang Trung']),
    ('nguyen-anh_ref.png', ['Nguyễn Ánh']),
    ('le-chieu-thong_ref.png', ['Lê Chiêu Thống']),
    ('ton-si-nghi_ref.png', ['Tôn Sĩ Nghị']),
    ('le-ngoc-han_ref.png', ['Lê Ngọc Hân','công chúa']),
    ('tay-son-soldiers-and-common-people_ref.png', ['Tây Sơn','nghĩa quân','quân sĩ','dân chúng','người lính']),
    ('xiem-and-qing-armies_ref.png', ['quân Xiêm','Xiêm','quân Thanh','Thanh','Sầm Nghi Đống'])
]


def log(msg):
    RUN_LOG.parent.mkdir(parents=True, exist_ok=True)
    line = f"[{datetime.now().isoformat(timespec='seconds')}] {msg}"
    print(line, flush=True)
    with RUN_LOG.open('a', encoding='utf-8') as fh:
        fh.write(line + '\n')


def refs_for_scene(text):
    refs=[]
    lower=text.lower()
    for file, words in KEYWORDS:
        if any(w.lower() in lower for w in words):
            p=PROJECT/'images/refs'/file
            if p.exists():
                refs.append(str(p))
    return refs[:3]


def build_prompt(scene):
    narration = scene.get('narration') or scene.get('text','')
    if scene.get('type') == 'heading':
        return f"""[VISUAL STYLE]
Light Vietnamese old-calligraphy title-card on warm antique paper, subtle ink wash and small seal/stamp accent, airy text with breathing room, not heavy black title slam, not clean modern typography. 16:9 horizontal canvas.

[HISTORICAL GROUNDING]
Late 18th-century Dai Viet / Tay Son historical memory, antique manuscript paper, Vietnamese calligraphy mood.

[SCENE ACTION / FRAMING]
Create a chapter heading image for this exact Vietnamese title: {narration}. Keep the card elegant, readable, spacious, and handcrafted.

[CHARACTER IDENTITY]
No character portrait needed unless a very subtle historical silhouette supports the title.

{NEG}"""
    battle_words = ['trận','quân','đánh','chiến','pháo','đồn','thủy quân','xâm lược','tháo chạy']
    kind = 'battle' if any(w in narration.lower() for w in battle_words) else 'generic'
    action = f"One cinematic narrative {'battle ' if kind=='battle' else ''}scene showing this exact narration beat: {narration}. Clear environment, clear focal action, readable emotional staging, historically grounded props and setting, suitable for a story video frame."
    char = "Use attached character references only for identity consistency when applicable: face, age, hair, expression tendency, costume details, and armor language. Do not reproduce the reference sheets themselves."
    return f"""{STYLE}
[SCENE ACTION / FRAMING]
{action}

[CHARACTER IDENTITY]
{char}

{NEG}"""


def generate(scene):
    sid=scene['scene_id']
    out=PROJECT/'images/scenes'/f'{sid}.png'
    if out.exists() and out.stat().st_size>1000:
        return {'scene_id':sid,'status':'skipped_existing','output_path':str(out)}
    cmd=[sys.executable,str(GEN_SCRIPT),'--prompt',build_prompt(scene),'--output',str(out),'--size','auto','--quality','auto','--background','auto','--image-detail','high','--output-format','png','--n','1']
    for ref in refs_for_scene(scene.get('narration') or scene.get('text','')):
        cmd += ['--input-ref', ref]
    proc=subprocess.run(cmd,text=True,capture_output=True,timeout=480)
    if proc.returncode!=0:
        return {'scene_id':sid,'status':'failed','error':(proc.stderr or proc.stdout)[-2000:]}
    if not out.exists() or out.stat().st_size<1000:
        return {'scene_id':sid,'status':'failed_empty_output'}
    return {'scene_id':sid,'status':'generated','output_path':str(out),'bytes':out.stat().st_size}


def main():
    if not os.environ.get('GEN_IMG_API_KEY'):
        raise SystemExit('GEN_IMG_API_KEY missing')
    ref_plan=json.loads(REF_PLAN_PATH.read_text(encoding='utf-8'))
    if not ref_plan.get('approved_for_scene_images'):
        raise SystemExit('Step 05 refs not approved for scene images')
    scenes=json.loads(SCENES_PATH.read_text(encoding='utf-8'))['scenes'][:LIMIT]
    manifest={'project_id':'31052026-001-Nguyen-Hue-Quang-Trung','step':'6_limited_first50','limit':LIMIT,'workers':WORKERS,'started_at':datetime.now().isoformat(timespec='seconds'),'status':'running','results':[]}
    MANIFEST_PATH.write_text(json.dumps(manifest,ensure_ascii=False,indent=2),encoding='utf-8')
    log(f'Start Step 06 limited first {LIMIT} scenes with {WORKERS} workers')
    with ThreadPoolExecutor(max_workers=WORKERS) as ex:
        futs={ex.submit(generate,s):s for s in scenes}
        for fut in as_completed(futs):
            res=fut.result()
            manifest['results'].append(res)
            log(f"{res['scene_id']} {res['status']}")
            MANIFEST_PATH.write_text(json.dumps(manifest,ensure_ascii=False,indent=2),encoding='utf-8')
            if res['status'].startswith('failed'):
                manifest['status']='failed'
                MANIFEST_PATH.write_text(json.dumps(manifest,ensure_ascii=False,indent=2),encoding='utf-8')
                return 1
    ok=sum(1 for r in manifest['results'] if r['status'] in ('generated','skipped_existing'))
    manifest['completed_at']=datetime.now().isoformat(timespec='seconds')
    manifest['status']='completed_limited_50_pending_review' if ok==LIMIT else 'incomplete'
    manifest['generated_or_existing_count']=ok
    MANIFEST_PATH.write_text(json.dumps(manifest,ensure_ascii=False,indent=2),encoding='utf-8')
    log(f'Step 06 limited complete: {ok}/{LIMIT}; stopping before scene_051 and thumbnails')
    return 0 if ok==LIMIT else 1

if __name__=='__main__':
    raise SystemExit(main())
