#!/usr/bin/env python3
from __future__ import annotations
import argparse,json,time,urllib.request,urllib.error,uuid,wave
from pathlib import Path
from project_runtime import atomic_write_json,require_project_root,valid_wav,save_stage
VOICE='http://192.168.40.32:7861/voice/truong-giang'
def multipart(text:str,boundary:str)->bytes:
 parts=[]
 for k,v in [('text',text),('style','tu_nhien'),('speed','1'),('denoise','true')]:
  parts += [f'--{boundary}\r\nContent-Disposition: form-data; name="{k}"\r\n\r\n{v}\r\n'.encode()]
 parts.append(f'--{boundary}--\r\n'.encode());return b''.join(parts)
def main():
 ap=argparse.ArgumentParser();ap.add_argument('project');ap.add_argument('--ids',nargs='*',type=int);a=ap.parse_args();p=require_project_root(Path(a.project));m=json.loads((p/'narration/narration.json').read_text());items=m['items'];wanted=set(a.ids or [x['id'] for x in items]);results=[]
 for x in items:
  if x['id'] not in wanted:continue
  out=Path(x['audio_path']);out=out if out.is_absolute() else p/out
  if valid_wav(out):results.append({'id':x['id'],'status':'existing'});continue
  out.parent.mkdir(parents=True,exist_ok=True);ok=False;err=''
  for attempt in range(4):
   tmp=out.with_suffix('.tmp.wav');boundary='----Sticker'+uuid.uuid4().hex;req=urllib.request.Request(VOICE,data=multipart(x['text'],boundary),headers={'Content-Type':f'multipart/form-data; boundary={boundary}'},method='POST')
   try:
    with urllib.request.urlopen(req,timeout=240) as r:tmp.write_bytes(r.read())
    if valid_wav(tmp):tmp.replace(out);ok=True;break
    err='invalid_wav'
   except Exception as e:err=type(e).__name__
   finally:
    if tmp.exists():tmp.unlink()
   time.sleep(2**attempt)
  results.append({'id':x['id'],'status':'ok' if ok else 'fail','error':err if not ok else None})
 valid=[x['id'] for x in items if valid_wav((Path(x['audio_path']) if Path(x['audio_path']).is_absolute() else p/x['audio_path']))];report={'status':'PASS' if len(valid)==len(items) else 'FAIL','expected':len(items),'valid':valid,'results':results};atomic_write_json(p/'logs/tts_gate.json',report)
 if report['status']=='PASS':save_stage(p,'TTS','PASS',{'count':len(valid)})
 print(json.dumps(report));raise SystemExit(0 if report['status']=='PASS' else 1)
if __name__=='__main__':main()
