"""Transcribe an Arabic recording with Kalemio; save JSON and SRT beside it.

    pip install requests
    export KALEMIO_API_KEY='YOUR_API_KEY'
    python kalemio_quickstart.py conversation.m4a
"""
import hashlib
import os
import sys
import time
from pathlib import Path

import requests

API = os.environ.get("KALEMIO_API_BASE", "https://kalemio.app")
AUTH = {"Authorization": "Bearer " + os.environ["KALEMIO_API_KEY"]}
recording = Path(sys.argv[1])
audio = recording.read_bytes()
# The same file always sends the same key, so running this again after an
# interruption returns the first job instead of starting and billing another.
# A second argument, such as retry1, makes a new key to transcribe it afresh.
key = "quickstart-" + hashlib.sha256(audio).hexdigest()[:32]
if len(sys.argv) > 2:
    key += "-" + sys.argv[2]


def message(response):
    try:
        return response.json().get("error", response.text)
    except ValueError:
        return response.text


def stop(what, response):
    sys.exit(f"{what} ({response.status_code}): {message(response)}")


def retryable(response):
    if response.status_code == 429:  # The Free plan's own limits don't clear soon.
        return not response.json().get("code", "").startswith("free_")
    return response.status_code >= 500


def send(method, path, headers=None, **options):
    """Sends a request; rate limits and server errors are retried with backoff."""
    headers = {**AUTH, **(headers or {})}
    for attempt in range(6):
        try:
            response = requests.request(method, API + path, headers=headers,
                                        timeout=120, **options)
        except requests.RequestException as error:
            sys.exit(f"Network error: {error}. Run this again: the same file "
                     "follows the same job.")
        if not retryable(response) or attempt == 5:
            return response
        time.sleep(float(response.headers.get("Retry-After", 2 ** attempt)))


response = send("POST", "/v1/transcriptions",
                headers={"Idempotency-Key": key},
                files={"file": (recording.name, audio)},
                data={"speakers": "auto"})
if response.status_code == 402:
    sys.exit(f"Not enough minutes: {message(response)} Nothing was charged. Add "
             f"a plan or minutes at {API}/developers/portal/ and run this again.")
if response.status_code != 202:
    stop("Upload refused", response)
job = response.json()
print(f"Job {job['id']} accepted ({job['processing']} processing)")

delay = 3
while job["status"] in ("queued", "running"):
    time.sleep(delay)
    delay = min(delay * 2, 30)  # Free plan jobs can wait in a queue for a while.
    response = send("GET", f"/v1/transcriptions/{job['id']}")
    if not response.ok:
        stop("Status check failed", response)
    job = response.json()
if job["status"] != "completed":
    sys.exit(f"Job {job['id']} {job['status']}: {job.get('error', '')}")

for name, suffix in (("result", ".json"), ("srt", ".srt")):
    response = send("GET", f"/v1/transcriptions/{job['id']}/{name}")
    if not response.ok:
        stop("Download failed", response)
    recording.with_suffix(suffix).write_bytes(response.content)
    print("Saved", recording.with_suffix(suffix))

