#!/usr/bin/env python3
from __future__ import annotations

import argparse
import json
import math
import sys
from pathlib import Path
from typing import NoReturn, Sequence, TextIO

from account_registry import Account, AccountRef
from claude_health_client import ClaudeHealthClient
from health_client import AccountSnapshot, NamedLimit


REQUIRED_KEYS = (
    "status",
    "five_hour_available",
    "seven_day_available",
    "five_hour_reset_valid",
    "seven_day_reset_valid",
    "named_limit_count",
)


class _ArgumentParser(argparse.ArgumentParser):
    def error(self, message: str) -> NoReturn:
        self.print_usage(sys.stderr)
        raise _UsageError(f"{self.prog}: {message}")


class _UsageError(Exception):
    pass


def _parser() -> argparse.ArgumentParser:
    parser = _ArgumentParser(prog="verify_claude_health", add_help=True)
    parser.add_argument(
        "--account-home",
        required=True,
        help="Path to the Claude account home directory.",
    )
    return parser


def _build_account(account_home: Path) -> Account:
    return Account(
        AccountRef("claude", "probe"),
        "probe",
        account_home,
        None,
        None,
        None,
    )


def _limit_by_kind(snapshot: AccountSnapshot, kind: str) -> NamedLimit | None:
    for limit in snapshot.named_limits:
        if limit.kind == kind and limit.active:
            return limit
    return None


def _reset_valid(limit: NamedLimit | None) -> bool:
    if limit is None:
        return False
    reset = limit.resets_at
    return isinstance(reset, (int, float)) and not isinstance(reset, bool) and math.isfinite(reset)


def _payload(snapshot: AccountSnapshot) -> dict[str, object]:
    five_hour = _limit_by_kind(snapshot, "five_hour")
    seven_day = _limit_by_kind(snapshot, "seven_day")
    payload: dict[str, object] = {
        "status": snapshot.status.value,
        "five_hour_available": five_hour is not None,
        "seven_day_available": seven_day is not None,
        "five_hour_reset_valid": _reset_valid(five_hour),
        "seven_day_reset_valid": _reset_valid(seven_day),
        "named_limit_count": sum(1 for limit in snapshot.named_limits if limit.active),
    }
    if tuple(payload) != REQUIRED_KEYS:
        raise RuntimeError("unexpected payload schema")
    return payload


def _success(payload: dict[str, object]) -> bool:
    return payload == {
        "status": "ok",
        "five_hour_available": True,
        "seven_day_available": True,
        "five_hour_reset_valid": True,
        "seven_day_reset_valid": True,
        "named_limit_count": payload["named_limit_count"],
    }


def main(
    argv: Sequence[str] | None = None,
    *,
    stdout: TextIO | None = None,
    stderr: TextIO | None = None,
) -> int:
    args = list(sys.argv if argv is None else argv)
    out = sys.stdout if stdout is None else stdout
    err = sys.stderr if stderr is None else stderr
    parser = _parser()

    try:
        namespace = parser.parse_args(args[1:])
    except _UsageError as exc:
        err.write(f"{exc}\n")
        return 2
    except SystemExit as exc:
        return int(exc.code) if isinstance(exc.code, int) else 2

    account_home = Path(namespace.account_home).expanduser()
    if not account_home.is_dir():
        err.write("verify_claude_health: --account-home must point to a directory\n")
        return 2

    snapshot = ClaudeHealthClient().fetch(_build_account(account_home))
    payload = _payload(snapshot)
    json.dump(payload, out, separators=(",", ":"))
    out.write("\n")
    return 0 if _success(payload) else 1


if __name__ == "__main__":
    raise SystemExit(main())
