#!/usr/bin/env python3
"""Submit missing scene 01 atmosphere images to MXAI sequentially.
Only encodes reference files for API input and downloads API outputs; no local image editing/processing.
"""
import base64, json, mimetypes, os, pathlib, re, time, urllib.error, urllib.request
BASE='https://mcp.mxai.cn'
ROOT=pathlib.Path('/Users/bot1/AI Work/02_projects/active/proj-coin-pouch-video')
OUTDIR=ROOT/'outputs/scene-01-base/scene01-atmosphere-redo-20260522-161016'
OUTDIR.mkdir(parents=True, exist_ok=True)
PROMPT="""参考白底排版图和10张原始钱币图，生成一张 3:4 竖版场景01氛围图。

画面是一组10枚不同形态的古钱币文物原型，错落摆放在深色暖调桌面/展台上。保留10枚钱币的形态差异：桥形灰金属钱、贝形金色钱、布币/铲形钱、青铜绿锈铲形钱、圆形方孔钱、黑色椭圆刻纹钱、金色裂纹圆片等都要可辨识，不能统一成同一种圆形铜钱。

构图参考白底排版图的数量、位置和错落关系。10枚钱币需要可数、可辨，至少6枚完整或大部分可见，其余可以轻微搭边、压住、半遮挡，但轮廓、孔洞、颜色或纹样仍能辨认。允许自然叠放和半遮挡，画面要丰富，但不要堆成一团。

氛围为文博奇幻、微缩世界、温暖神秘。深棕黑色桌面，细腻纹理和轻微尘埃颗粒。一束柔和暖金光从左上方斜照，扫过钱币边缘和纹样，形成低调金色高光。背景虚化，浅景深，微距摄影质感，整体有高级产品广告感和电影感。

镜头为微距近景，轻微斜俯拍视角，像视频开场第一帧。画面中心有视觉焦点，但不要只突出一枚钱币，需要让10枚钱币作为一个群体被看见。

避免：文字、水印、边框、拼贴感、白底素材板、钱币堆成一团、10枚变成同一种圆形铜钱、明显悬浮、主体模糊、廉价卡通感。"""
REFS=[ROOT/'outputs/scene-01-base/scene01-ten-coin-staggered-layout-feathered-20260522-135944.png']+sorted((ROOT/'assets/reference-coins/raw').glob('*.jpg'))

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

def req_json(method,path,key,body=None,timeout=180):
    headers={'Content-Type':'application/json; charset=utf-8','Authorization':'Bearer '+key}
    data=None if body is None else json.dumps(body,ensure_ascii=False).encode('utf-8')
    req=urllib.request.Request(BASE+path,data=data,method=method,headers=headers)
    try:
        with urllib.request.urlopen(req,timeout=timeout) as r:
            return json.loads(r.read().decode('utf-8',errors='replace'))
    except urllib.error.HTTPError as e:
        raw=e.read().decode('utf-8',errors='replace')
        raise RuntimeError(f'HTTP {e.code} {path}: '+re.sub(r'nb_[A-Za-z0-9_\-]+','nb_********',raw))

def data_obj(x): return x.get('data',x) if isinstance(x,dict) else {}
def serial(x):
    d=data_obj(x); return d.get('serial_no') or d.get('serialNo') or d.get('serial') or x.get('serial_no')
def download(url,dest):
    with urllib.request.urlopen(urllib.request.Request(url,headers={'User-Agent':'HermesVideo/1.0'}),timeout=180) as r:
        dest.write_bytes(r.read())

def one(label,model,input_images,key):
    body={'prompt':PROMPT,'model':model,'aspect_ratio':'3:4','resolution':'1K','quality':'high','count':1,'input_images':input_images}
    sn=serial(req_json('POST','/mcp/api/generate/image',key,body))
    print(json.dumps({'event':'submitted','label':label,'model':model,'serial_no':sn},ensure_ascii=False),flush=True)
    deadline=time.time()+900
    while time.time()<deadline:
        t=data_obj(req_json('GET',f'/mcp/api/task/{sn}',key,timeout=60)); st=str(t.get('status'))
        print(json.dumps({'event':'poll','label':label,'serial_no':sn,'status':st},ensure_ascii=False),flush=True)
        if st=='2':
            urls=t.get('image_urls') or t.get('images') or t.get('urls') or []
            if isinstance(urls,str): urls=[urls]
            files=[]
            for i,u in enumerate(urls,1):
                ext='.png'; m=re.search(r'\.(png|jpg|jpeg|webp)(?:\?|$)',u,re.I)
                if m: ext='.'+m.group(1).lower().replace('jpeg','jpg')
                dest=OUTDIR/f'{label}{ext}' if len(urls)==1 else OUTDIR/f'{label}-{i:02d}{ext}'
                download(u,dest); files.append(str(dest))
            return {'label':label,'model':model,'serial_no':sn,'status':'completed','files':files}
        if st in ('3','4'):
            return {'label':label,'model':model,'serial_no':sn,'status':'failed','task':t}
        time.sleep(5)
    return {'label':label,'model':model,'serial_no':sn,'status':'timeout'}

def main():
    key=os.environ.get('MX_AI_API_KEY')
    if not key: raise SystemExit('MX_AI_API_KEY missing')
    input_images=[data_url(p) for p in REFS]
    jobs=[('nanobanana-02','nano-2.0-pro'),('nanobanana-03','nano-2.0-pro'),('gpt2image-02','gpt-image-2'),('gpt2image-03','gpt-image-2')]
    res=[]
    for idx,(label,model) in enumerate(jobs):
        res.append(one(label,model,input_images,key))
        if idx < len(jobs)-1:
            print(json.dumps({'event':'interval_sleep','seconds':20},ensure_ascii=False),flush=True)
            time.sleep(20)
    summary={'ok':True,'outdir':str(OUTDIR),'results':res}
    (OUTDIR/'mxai-generation-summary-extra.json').write_text(json.dumps(summary,ensure_ascii=False,indent=2),encoding='utf-8')
    print('FINAL_JSON_START'); print(json.dumps(summary,ensure_ascii=False,indent=2)); print('FINAL_JSON_END')
if __name__=='__main__': main()
