#!/usr/bin/env python3
"""Minimal authenticated Sonilo usage dashboard.

Reads account services and usage from the server side. Never expose SONILO_API_KEY
to browser JavaScript or public logs.
Status handling: 401 is auth_required/auth_invalid, 402 is insufficient balance,
403 is service disabled/forbidden, 404 means check the https://api.sonilo.com/v1
base URL, and 429 is rate limit with Retry-After/backoff.
"""

import json
import os
import random
import sys
import time
import urllib.error
import urllib.request


API_BASE = os.getenv("SONILO_API_BASE", "https://api.sonilo.com/v1").rstrip("/")
API_KEY = os.getenv("SONILO_API_KEY")
USER_AGENT = os.getenv("SONILO_USER_AGENT", "SoniloExample/1.0 (+https://sonilo.com/docs)")


def require_api_key() -> str:
    if not API_KEY:
        raise SystemExit("SONILO_API_KEY is required")
    return API_KEY


def retry_delay(attempt: int, retry_after: str | None) -> float:
    if retry_after:
        try:
            return max(0.0, float(retry_after))
        except ValueError:
            pass
    return min(30.0, (2 ** attempt) + random.random())


def parse_error(exc: urllib.error.HTTPError) -> str:
    body = exc.read().decode("utf-8", errors="replace")
    try:
        parsed = json.loads(body)
        return parsed.get("message") or parsed.get("error") or body
    except json.JSONDecodeError:
        return body or exc.reason


def get_json(path: str) -> dict:
    for attempt in range(5):
        request = urllib.request.Request(
            f"{API_BASE}{path}",
            method="GET",
            headers={
                "Authorization": f"Bearer {require_api_key()}",
                "Accept": "application/json",
                "User-Agent": USER_AGENT,
            },
        )
        try:
            with urllib.request.urlopen(request, timeout=60) as response:
                return json.loads(response.read().decode("utf-8"))
        except urllib.error.HTTPError as exc:
            message = parse_error(exc)
            if exc.code == 401:
                raise SystemExit(f"auth_invalid: check SONILO_API_KEY and Authorization header: {message}")
            if exc.code == 403:
                raise SystemExit(f"service_disabled/forbidden: API key is valid but this account cannot access the requested service or workspace: {message}")
            if exc.code == 402:
                raise SystemExit(f"insufficient_balance: {message}")
            if exc.code == 429 and attempt < 4:
                time.sleep(retry_delay(attempt, exc.headers.get("Retry-After")))
                continue
            if exc.code == 404:
                raise SystemExit(f"not_found: check API_BASE uses https://api.sonilo.com/v1, not a docs URL: {message}")
            raise SystemExit(f"Sonilo API failed with HTTP {exc.code}: {message}")

    raise SystemExit("Sonilo API failed after retries")


def main() -> None:
    services = get_json("/account/services")
    usage = get_json(f"/account/usage?days={os.getenv('SONILO_USAGE_DAYS', '30')}")

    dashboard = {
        "services": services,
        "usage": usage,
        "notes": [
            "Keep SONILO_API_KEY server-side.",
            "Use services to disable unsupported generation actions.",
            "Use usage to show remaining capacity before expensive batch generation.",
        ],
    }
    print(json.dumps(dashboard, indent=2, sort_keys=True))


if __name__ == "__main__":
    try:
        main()
    except KeyboardInterrupt:
        sys.exit("interrupted")
