# Python 3.10+, standard library only. Persist FOLEYIX_REQUEST_KEY before running.
# Keep the same request key and input after a lost response or API key rotation.
import json, os, time, urllib.request, urllib.error, urllib.parse
key, request_key = os.environ['FOLEYIX_API_KEY'], os.environ['FOLEYIX_REQUEST_KEY']
base = 'https://foleyix.com'
class NoRedirect(urllib.request.HTTPRedirectHandler):
    def redirect_request(self, req, fp, code, msg, headers, newurl):
        raise RuntimeError('Unexpected redirect')
opener = urllib.request.build_opener(NoRedirect)
def request(path, body=None):
    headers = {'Authorization': 'Bearer ' + key}
    if body is not None:
        headers.update({'Content-Type': 'application/json', 'Idempotency-Key': request_key})
    data = None if body is None else json.dumps(body).encode('utf-8')
    try:
        return opener.open(urllib.request.Request(base + path, data=data, headers=headers), timeout=90).read()
    except urllib.error.HTTPError as error:
        raise RuntimeError(f'HTTP {error.code}: {error.read().decode()}') from error
job = json.loads(request('/api/v1/generations', {'prompt': 'A quiet forest with birds singing, 3 seconds.', 'mode': 'ambience'}))['job']
deadline = time.monotonic() + 900
while job['status'] in ('queued', 'running'):
    if time.monotonic() > deadline:
        raise RuntimeError(f"Timeout: keep checking task {job['id']}; do not recreate it.")
    time.sleep(5)
    job = json.loads(request('/api/v1/jobs/' + urllib.parse.quote(job['id'], safe='')))['job']
if job['status'] != 'succeeded' or not job['resultAvailable'] or not job['downloadUrl']:
    raise RuntimeError(f"Task {job['id']}: {job['status']}; do not automatically resubmit.")
url = urllib.parse.urlsplit(job['downloadUrl'])
path = '/api/v1/jobs/' + urllib.parse.quote(job['id'], safe='') + '/audio'
if url.scheme != 'https' or url.netloc != 'foleyix.com' or url.path != path or url.query or url.fragment:
    raise RuntimeError('Unexpected download URL')
audio = request(path)
if audio[:4] != b'RIFF' or audio[8:12] != b'WAVE':
    raise RuntimeError('Invalid WAV')
with open('foleyix.wav', 'wb') as output:
    output.write(audio)
print(f"Saved {len(audio)} bytes from task {job['id']}; {job['durationSeconds']} seconds.")
