"""FrameGate video client. Python 3.10+; pip install requests.
Credentials are read only from FRAMEGATE_API_KEY, never saved to the state file.
Keep one state file per business request. Reuse it after network interruption.
"""
import argparse
import json
import os
from pathlib import Path
import time
import uuid
import requests

parser = argparse.ArgumentParser()
parser.add_argument('--payload', required=True, help='UTF-8 JSON video request')
parser.add_argument('--state', required=True, help='Persistent state file for one request')
parser.add_argument('--wait-seconds', type=int, default=1800)
args = parser.parse_args()
base = os.environ.get('FRAMEGATE_BASE_URL', 'https://api.myanimforge.com').rstrip('/')
key = os.environ['FRAMEGATE_API_KEY']
payload = json.loads(Path(args.payload).read_text(encoding='utf-8-sig'))
state_path = Path(args.state)
if state_path.exists():
    state = json.loads(state_path.read_text(encoding='utf-8'))
    if state['payload'] != payload or state['base_url'] != base:
        raise SystemExit('This state file belongs to another request. Do not change its payload.')
else:
    state = {'base_url': base, 'payload': payload, 'idempotency_key': str(uuid.uuid4())}
    # Exclusive creation prevents accidentally replacing another request state.
    with state_path.open('x', encoding='utf-8') as f:
        json.dump(state, f, ensure_ascii=False, indent=2)

def save():
    temporary = state_path.with_suffix(state_path.suffix + '.tmp')
    temporary.write_text(json.dumps(state, ensure_ascii=False, indent=2), encoding='utf-8')
    temporary.replace(state_path)

session = requests.Session()
session.headers['Authorization'] = 'Bearer ' + key
def checked(response):
    if not response.ok:
        print('HTTP', response.status_code, 'Trace', response.headers.get('X-Request-ID'))
        print(response.text)
        raise SystemExit('Stopped. Keep the state file and idempotency key; do not resubmit with a new key.')
    return response.json()

try:
    if not state.get('task_id'):
        # This POST is attempted once per run, with the same persistent key after a restart.
        result = checked(session.post(base + '/v1/videos', json=payload,
            headers={'Idempotency-Key': state['idempotency_key']}, timeout=(10, 240)))
        state['task_id'] = result['id']
        save()
    print('Task ID:', state['task_id'])
    deadline = time.monotonic() + args.wait_seconds
    while time.monotonic() < deadline:
        response = session.get(base + '/v1/videos/' + state['task_id'], timeout=(10, 30))
        if response.status_code == 429:
            time.sleep(min(120, int(response.headers.get('Retry-After', '60'))))
            continue
        result = checked(response)
        state['last_result'] = result
        save()
        status = result['status']
        billing_status = result['billing']['status']
        print('Execution:', status, 'Billing:', billing_status)
        if status == 'succeeded' or billing_status == 'settled':
            print(json.dumps(result, ensure_ascii=False, indent=2))
            if billing_status != 'settled':
                print('Output is ready; billing needs review. Contact support with the task ID.')
            break
        if status in ('failed', 'unknown') or billing_status in ('pending', 'released'):
            print(json.dumps(result, ensure_ascii=False, indent=2))
            print('Stopped. Contact support if billing is pending. Do not create a duplicate job.')
            break
        time.sleep(10)
    else:
        print('Local waiting ended; the server task is not cancelled. Run the same command to continue querying.')
except requests.RequestException as exc:
    print('Network error:', type(exc).__name__)
    print('Preserve the state file. Reuse this command; do not switch to a new idempotency key.')
    raise SystemExit(1)
finally:
    session.close()
