#!/usr/bin/env python3
"""Upload, poll, and download with Python's standard library."""

import json
import os
from pathlib import Path
import sys
import time
import urllib.error
import urllib.request
import uuid

BASE_URL = os.getenv(
    "PYDECODE_BASE_URL",
    "https://pydecode.com/api/v1",
).rstrip("/")
TERMINAL_STATES = {"succeeded", "partial", "failed", "expired"}


def api_request(url: str, *, data: bytes | None = None, headers=None, method="GET"):
    request_headers = {
        "Authorization": f"Bearer {os.environ['PYDECODE_API_KEY']}",
        **(headers or {}),
    }
    request = urllib.request.Request(
        url, data=data, headers=request_headers, method=method
    )
    try:
        return urllib.request.urlopen(request)
    except urllib.error.HTTPError as error:
        detail = error.read().decode("utf-8", errors="replace")
        raise SystemExit(f"API request failed ({error.code}): {detail}") from error


def main() -> None:
    if len(sys.argv) != 2:
        raise SystemExit("Usage: pydecode-python.py module.pyc|archive.zip")

    source = Path(sys.argv[1])
    if source.suffix.lower() not in {".pyc", ".zip"}:
        raise SystemExit("Input must end in .pyc or .zip")

    with api_request(
        f"{BASE_URL}/decompile",
        data=source.read_bytes(),
        method="POST",
        headers={
            "Content-Type": "application/octet-stream",
            "Idempotency-Key": str(uuid.uuid4()),
            "X-Filename": source.name,
        },
    ) as response:
        job = json.load(response)["job"]
    print(f"Created {job['id']} ({job['state']})")

    while job["state"] not in TERMINAL_STATES:
        time.sleep(2)
        with api_request(f"{BASE_URL}/jobs/{job['id']}") as response:
            job = json.load(response)["job"]
        print(f"State: {job['state']}")

    if not job.get("result_url"):
        raise SystemExit(f"Job ended without a result: {job['state']}")

    output = source.with_name(f"{source.stem}-recovered.zip")
    with api_request(job["result_url"]) as response:
        output.write_bytes(response.read())
    print(f"Saved {output}")


if __name__ == "__main__":
    main()
