"""Reuse music-lab's resumable ReAPI batch helper for Notification's seven posts."""
import argparse, importlib.util, json
from pathlib import Path

ROOT = Path(__file__).resolve().parent
WORK = ROOT / 'production/seedance'
WORK.mkdir(parents=True, exist_ok=True)
spec = importlib.util.spec_from_file_location('reapi_jobs', ROOT.parent / 'recovering-hyperaddict/reapi_jobs.py')
jobs = importlib.util.module_from_spec(spec)
spec.loader.exec_module(jobs)
jobs.ROOT = WORK

def prepare():
    path = WORK / 'clip-requests.json'
    if path.exists():
        return
    plan = json.loads((ROOT / 'production/plan.json').read_text())
    frames = json.loads((ROOT / 'editor-data.json').read_text())
    shots = []
    for shot in plan['shots']:
        n = shot['frame']
        poem = frames[n-1]['poem']
        # Speech is supplied only by the separately validated ElevenLabs track.
        prompt = shot['prompt'] + '\n\nAUDIO OVERRIDE: silent picture only. Do not generate dialogue, voiceover, music or speech. Acting and mouth movement are visual performance only. All spoken words will be supplied separately in the edit from this exact poem excerpt, without additions:\n' + poem
        shots.append({'shot': f'{n:02d}', 'frame': n, 'name': shot['title'], 'output_file': f'clips/frame-{n:02d}.mp4', 'status': 'prepared', 'request': {
            'model':'doubao-seedance-2.5-face', 'prompt':prompt, 'duration':shot['seconds'],
            'omni_reference_task_type':'reference', 'size':'9:16', 'resolution':'720p', 'generate_audio':False, 'output_format':'mp4',
            'watermark':False, 'return_last_frame':True, 'content_filter':True,
            'image_with_roles':[{'url':'https://notification-storyboard.pages.dev/'+shot['reference'], 'role':'reference_image'}]
        }})
    jobs.save(path, {'provider':'reapi.ai','model':'doubao-seedance-2.5-face','total_seconds':79,'estimated_usd':21.093,'pricing_source':'https://reapi.ai/models/seedance-2-5','shots':shots})

def manifest():
    items=[]
    for shot in jobs.shots():
        state=WORK/'jobs'/(shot['shot']+'.json')
        rec=json.loads(state.read_text()) if state.exists() else {}
        response=rec.get('response',{})
        items.append({'frame':shot['frame'],'status':response.get('status',rec.get('state','prepared')),'task_id':response.get('id'), 'file':str((WORK/shot['output_file']).relative_to(ROOT)) if rec.get('local_file') else None,'usage':response.get('usage'), 'error':response.get('error')})
    jobs.save(ROOT/'production/seedance-manifest.json',{'model':'doubao-seedance-2.5-face','audio':'disabled; exact poem voiceover supplied separately','clips':items})

if __name__ == '__main__':
    p=argparse.ArgumentParser();p.add_argument('action',choices=['prepare','submit','poll']);args=p.parse_args()
    prepare()
    if args.action=='submit':
        for shot in jobs.shots():
            result=jobs.submit(shot['shot'])
            if result.get('state')=='rejected':break
    elif args.action=='poll':
        jobs.poll();jobs.download_completed()
    manifest()
