"""claude.ai subscription-usage ceilings — the single source of truth.

ONE place that reads the (undocumented) OAuth usage endpoint and decides whether
a usage window has crossed its soft stop-before-429 ceiling. Imported by BOTH the
halacha drain (`scripts/drain_halacha_queue.py`) and its supervisor
(`scripts/halacha_drain_supervisor.py`) so the two never drift (G1/G2).

STRICTLY stdlib — no asyncpg / aiohttp / config imports. The supervisor runs as
plain system ``python3`` and imports this module directly; pulling in heavy deps
here would break that import. (``legal_mcp/__init__`` and ``services/__init__``
are intentionally empty, which is what makes the system-python import work.)

Soft ceilings (chair, 2026-06-15): stop the drain BEFORE a window exhausts so the
in-flight case finishes on the remaining quota and the drain idles until reset,
instead of hammering 429 (which burns retries and leaves cases half-extracted).
5-hour ("hourly session") window stops at 75%, the weekly windows at 65%.
Overridable via env for ops tuning without a redeploy.
"""
import json
import os
import urllib.request
from datetime import datetime, timezone

# claude.ai subscription usage. The token lives in the CLI's own credentials
# file; the claude-code User-Agent is REQUIRED — without it the request lands in
# an aggressively rate-limited bucket and 429s. Unofficial endpoint: may change,
# so every caller must tolerate a None return and fall back.
CLAUDE_CRED_PATH = "/home/chaim/.claude/.credentials.json"
OAUTH_USAGE_URL = "https://api.anthropic.com/api/oauth/usage"
USAGE_UA = "claude-code/2.1.177"


def _env_int(name: str, default: int) -> int:
    try:
        return int(os.environ.get(name, default))
    except (TypeError, ValueError):
        return default


# Reaching a ceiling is treated EXACTLY like 100% exhaustion (cooldown until that
# window's resets_at). Both weekly keys share one threshold; the per-model cap
# that's actually populated on this account is Sonnet (seven_day_opus is null) and
# the all-models seven_day cap is the backstop for Opus usage either way.
CEILING_FIVE_HOUR = _env_int("HALACHA_DRAIN_CEILING_5H", 75)
CEILING_WEEKLY = _env_int("HALACHA_DRAIN_CEILING_WEEKLY", 65)
USAGE_CEILINGS = {
    "five_hour": CEILING_FIVE_HOUR,
    "seven_day": CEILING_WEEKLY,
    "seven_day_sonnet": CEILING_WEEKLY,
}


def subscription_usage() -> dict | None:
    """Read the claude.ai subscription usage — the exact 5-hour / 7-day
    utilization the Claude Code UI shows — from the OAuth usage endpoint.

    Returns the parsed JSON (keys: five_hour, seven_day, seven_day_opus,
    seven_day_sonnet, extra_usage; each window → {utilization 0-100, resets_at})
    or None on ANY failure. Undocumented endpoint — every caller must tolerate
    None and fall back."""
    try:
        with open(CLAUDE_CRED_PATH) as f:
            token = json.load(f)["claudeAiOauth"]["accessToken"]
    except Exception:
        return None
    req = urllib.request.Request(OAUTH_USAGE_URL, headers={
        "Authorization": f"Bearer {token}",
        "User-Agent": USAGE_UA,              # required — else aggressive 429
        "anthropic-beta": "oauth-2025-04-20",
    })
    try:
        with urllib.request.urlopen(req, timeout=15) as resp:
            return json.loads(resp.read().decode("utf-8"))
    except Exception:
        return None


def ceiling_status(usage: dict) -> tuple[bool, datetime | None, str]:
    """Evaluate an already-fetched usage dict against USAGE_CEILINGS.

    Returns (over, earliest_reset_utc, detail):
      • over            — True iff ANY gated window is at/above its ceiling
      • earliest_reset  — soonest resets_at among the windows that are over (UTC),
                          or None
      • detail          — short log string, e.g. "5h=78%/75 weekly=40%/65"

    Takes the usage dict as a parameter (does NOT fetch) so the caller owns the
    single network read. null utilization → treated as 0% (window inactive)."""
    over, resets, parts = False, [], []
    label = {"five_hour": "5h", "seven_day": "weekly", "seven_day_sonnet": "weekly-sonnet"}
    for w, ceiling in USAGE_CEILINGS.items():
        info = usage.get(w) or {}
        util = info.get("utilization") or 0
        parts.append(f"{label.get(w, w)}={util:.0f}%/{ceiling}")
        if util >= ceiling:
            over = True
            r = info.get("resets_at")
            if r:
                try:
                    resets.append(datetime.fromisoformat(r).astimezone(timezone.utc))
                except Exception:
                    pass
    return over, (min(resets) if resets else None), " ".join(parts)
