#!/usr/bin/env python3
from pathlib import Path
import base64, json, os, time, urllib.request, urllib.error, mimetypes, shutil

PROJECT=Path('/data/video-pipeline/Youtube-Video-Maker/Project/26052026-001-Ngo-Quyen')
BASE=Path('/data/video-pipeline/Youtube-Video-Maker')
LOG=PROJECT/'logs/step_06_regenerate_gpt_only.log'
STATE=PROJECT/'logs/step_06_regenerate_gpt_only_state.json'

def log(msg):
    line=time.strftime('%Y-%m-%d %H:%M:%S')+' '+msg
    print(line, flush=True)
    with LOG.open('a',encoding='utf-8') as f: f.write(line+'\n')

def load_env():
    env=os.environ.copy()
    for env_file in [BASE/'.env', PROJECT/'.env']:
        if env_file.exists():
            for line in env_file.read_text(encoding='utf-8').splitlines():
                if '=' in line and not line.strip().startswith('#'):
                    k,v=line.split('=',1); env[k.strip()]=v.strip().strip('"').strip("'")
    return env

def data_url(path):
    p=Path(path); mime=mimetypes.guess_type(str(p))[0] or 'image/png'
    return 'data:%s;base64,%s' % (mime, base64.b64encode(p.read_bytes()).decode())

def payloads(text):
    out=[]
    for line in text.splitlines():
        line=line.strip()
        if line.startswith('data:'): line=line[5:].strip()
        if not line or line=='[DONE]': continue
        try: out.append(json.loads(line))
        except json.JSONDecodeError: pass
    if out: return out
    return [json.loads(text)]

def save_response(text,out):
    for pay in payloads(text):
        if isinstance(pay,dict) and pay.get('error'):
            raise RuntimeError(str(pay['error']))
        data=pay.get('data') if isinstance(pay,dict) else None
        if not data: continue
        item=data[0] if isinstance(data,list) else data
        if not isinstance(item,dict): continue
        b64=item.get('b64_json') or item.get('base64') or item.get('image_base64')
        url=item.get('url') or item.get('image_url')
        if b64:
            if b64.startswith('data:'): b64=b64.split(',',1)[1]
            Path(out).parent.mkdir(parents=True,exist_ok=True)
            Path(out).write_bytes(base64.b64decode(b64)); return
        if url:
            Path(out).parent.mkdir(parents=True,exist_ok=True)
            urllib.request.urlretrieve(url,out); return
    raise RuntimeError('No image in response')

def gen(prompt,out,refs=None,max_attempts=5):
    env=load_env(); base=env.get('GEN_IMG_BASE_URL','http://192.168.40.11:20128').rstrip('/'); key=env['GEN_IMG_API_KEY']
    body={'model':'cx/gpt-5.5-image','prompt':prompt,'n':1,'size':'auto','quality':'auto','background':'auto','image_detail':'high','output_format':'png'}
    if refs: body['image']=[data_url(r) for r in refs if Path(r).exists()]
    for attempt in range(1,max_attempts+1):
        try:
            log(f'GEN attempt={attempt} out={out}')
            req=urllib.request.Request(base+'/v1/images/generations',data=json.dumps(body).encode(),headers={'Content-Type':'application/json','Authorization':'Bearer '+key,'Accept':'text/event-stream'},method='POST')
            with urllib.request.urlopen(req,timeout=420) as r: text=r.read().decode('utf-8','ignore')
            save_response(text,out)
            log(f'DONE out={out}')
            return True
        except Exception as e:
            log(f'ERROR attempt={attempt} out={out} err={e}')
            time.sleep(min(90,15*attempt))
    return False

main_refs=[
'/data/video-pipeline/Youtube-Video-Maker/data/style-ref/main-scene/main-scene-ceremony-pavilion-river-01.jpg',
'/data/video-pipeline/Youtube-Video-Maker/data/style-ref/main-scene/main-scene-rally-river-army-01.jpg',
'/data/video-pipeline/Youtube-Video-Maker/data/style-ref/main-scene/main-scene-river-defense-stakes-fleet-01.jpg']
thumb_refs=[
'/data/video-pipeline/Youtube-Video-Maker/data/style-ref/thumbnail/thumbnail-biography-poster-gold-title-ink-splash-01.jpg',
'/data/video-pipeline/Youtube-Video-Maker/data/style-ref/thumbnail-historical-calligraphy-poster-le-lai-ref.jpg',
'/data/video-pipeline/Youtube-Video-Maker/data/style-ref/thumbnail-epic-history-vietnamese-ink-gold.jpg',
str(PROJECT/'characters/ngo_quyen_ref_v3_16x9.png')]

scene55_prompt = """Handcrafted Vietnamese brush-calligraphy historical chapter heading scene, GPT-generated only, 16:9 horizontal composition/canvas. Warm antique parchment paper, centered irregular ink-wash window, the visual content occupies about 65-70% of the page with 30-35% clean antique paper negative space. Light, airy, elegant, historically calm, soft black-brown ink variation, natural ink bleed, gentle watercolor wash, restrained edge splashes and subtle red seal-stamp accent. Show only this exact Vietnamese chapter heading text, large but not oversized: "Trước Giờ Quyết Chiến". Preserve all Vietnamese diacritics accurately. No ordinal numbering. Not modern typography, not subtitle card, not logo card, not watermark, not aggressive heavy-ink title slam, not edge-to-edge artwork, no extra fake letters."""
thumb16_prompt = """Epic dark Vietnamese historical biography poster thumbnail, GPT-generated final image, exact 16:9 horizontal thumbnail composition, inspired by dramatic Nguyễn Trãi historical poster style. Main subject: Ngô Quyền, heroic early 10th-century Vietnamese commander, large portrait occupying left/center-left, stern calm resolve, historically grounded Vietnamese facial features, topknot/warrior hair, dark lamellar armor and robe language consistent with the approved character reference. Background: Battle of Bạch Đằng, storm clouds, smoky tidal river, hidden wooden stakes, war boats, banners, soldiers, bronze/gold backlight, gritty parchment manuscript texture, black ink splash / grunge title panel. Large readable metallic-gold Vietnamese brush-calligraphy title text: "NGÔ QUYỀN" placed on the right/lower-right over dark ink splash. Use accurate Vietnamese diacritics. Dark sepia, bronze, black, aged gold palette. Not a scene-image negative-space layout, not cropped from scene, not screenshot, not placeholder, not modern design, no wrong foreign armor, no watermark, no logo."""
thumb9_prompt = """Epic dark Vietnamese historical biography poster thumbnail, GPT-generated final image, exact 9:16 vertical composition, inspired by dramatic Nguyễn Trãi historical poster style. Main subject: Ngô Quyền, heroic early 10th-century Vietnamese commander, large upper portrait, stern calm resolve, historically grounded Vietnamese facial features, topknot/warrior hair, dark lamellar armor and robe language consistent with the approved character reference. Background: Battle of Bạch Đằng, storm clouds, smoky tidal river, hidden wooden stakes, war boats, banners, soldiers, bronze/gold backlight, gritty parchment manuscript texture, black ink splash / grunge title panel. Large readable metallic-gold Vietnamese brush-calligraphy title text: "NGÔ QUYỀN" in lower half over dark ink splash. Use accurate Vietnamese diacritics. Dark sepia, bronze, black, aged gold palette. Not a scene-image negative-space layout, not cropped from scene, not screenshot, not placeholder, not modern design, no wrong foreign armor, no watermark, no logo."""

tasks=[
('scene_055', scene55_prompt, PROJECT/'images/scenes/scene_055.png', main_refs),
('thumb_16x9', thumb16_prompt, PROJECT/'output/thumbnails/thumb_16x9_final.png', thumb_refs),
('thumb_9x16', thumb9_prompt, PROJECT/'output/thumbnails/thumb_9x16_final.png', thumb_refs),
]
results=[]
for name,prompt,out,refs in tasks:
    if out.exists():
        bak=out.with_name(out.stem+'_invalid_overlay_backup'+out.suffix)
        if not bak.exists(): shutil.move(str(out), str(bak))
        else: out.unlink()
    ok=gen(prompt,str(out),refs)
    results.append({'name':name,'ok':ok,'path':str(out),'exists':out.exists(),'size':out.stat().st_size if out.exists() else 0})
    STATE.write_text(json.dumps({'status':'running' if len(results)<len(tasks) else 'done','results':results},ensure_ascii=False,indent=2),encoding='utf-8')
log('SUMMARY '+json.dumps(results,ensure_ascii=False))
