#!/usr/bin/env python3
"""Request a court observation and poll for its result. Never controls lights."""
import argparse
import json
import os
import time
import urllib.request

BASE_URL = "https://api.clutchapp.io/v1/clutchcam/court-status"


def post_json(path, token, body, timeout=15):
    request = urllib.request.Request(
        f"{BASE_URL}/{path}",
        data=json.dumps(body).encode("utf-8"),
        headers={"Authorization": f"Bearer {token}", "Content-Type": "application/json"},
        method="POST",
    )
    # urllib raises HTTPError for non-2xx responses. Callers must preserve light
    # state on this error; no failure is interpreted as an empty court.
    with urllib.request.urlopen(request, timeout=timeout) as response:
        return response.status, json.load(response)


def observe_court(device_id, token, wait_seconds=330, poll_interval=3):
    if not device_id or not token:
        raise ValueError("A device ID and bearer token are required")
    if wait_seconds <= 0 or poll_interval <= 0:
        raise ValueError("Polling interval and timeout must be positive")
    deadline = time.monotonic() + wait_seconds
    status, ack = post_json("request", token, {"device_id": device_id}, min(15, wait_seconds))
    if status != 202 or not ack.get("job_id") or ack.get("error"):
        raise RuntimeError("Court observation was not accepted")
    while True:
        remaining = deadline - time.monotonic()
        if remaining <= 0:
            raise TimeoutError("Court status unavailable; keep the current light state")
        time.sleep(min(poll_interval, remaining))
        remaining = deadline - time.monotonic()
        if remaining <= 0:
            raise TimeoutError("Court status unavailable; keep the current light state")
        status, result = post_json(
            "result", token,
            {"device_id": device_id, "job_id": ack["job_id"]},
            min(15, remaining),
        )
        if status == 200 and result.get("state") == "COMPLETED" and result.get("error") is None:
            court_status = result.get("court_status")
            if court_status not in {"OCCUPIED", "EMPTY", "LIGHTS_OFF"}:
                raise RuntimeError("Unknown court status; keep the current light state")
            return court_status
        if status != 202 or result.get("state") not in {"PENDING", "RUNNING"} or result.get("error"):
            raise RuntimeError("Court observation failed; keep the current light state")


if __name__ == "__main__":
    parser = argparse.ArgumentParser(description=__doc__)
    parser.add_argument("device_id", help="Clutch camera ID")
    args = parser.parse_args()
    token = os.environ.get("CLUTCH_API_TOKEN", "")
    if not token:
        parser.error("Set CLUTCH_API_TOKEN to your existing bearer token")
    print(observe_court(args.device_id, token))
