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

import argparse
import json
import os
import tempfile
from dataclasses import dataclass
from datetime import UTC, datetime
from pathlib import Path
from typing import Callable, Iterable

from account_registry import AccountRegistry, AccountRegistryKind, AuthorityMode
from authority_client import AuthorityConfigurationError, GatewayStatus, fetch_gateway_status

DEFAULT_TIMEOUT_SECONDS = 5.0


@dataclass(frozen=True)
class RenewalResult:
    attempted: int
    ready: int
    failed: int


def _registries() -> tuple[AccountRegistry, ...]:
    return (
        AccountRegistry(kind=AccountRegistryKind.CODEX),
        AccountRegistry(kind=AccountRegistryKind.CLAUDE),
    )


def renew_active_gateway_grants(
    registries: Iterable[AccountRegistry] | None = None,
    *,
    timeout_secs: float = DEFAULT_TIMEOUT_SECONDS,
    status_fetcher: Callable[..., GatewayStatus] = fetch_gateway_status,
) -> RenewalResult:
    attempted = ready = failed = 0
    for registry in _registries() if registries is None else registries:
        for _slug, binding in registry.authority_bindings():
            if binding.mode != AuthorityMode.SUBROUTER or binding.quiesced:
                continue
            attempted += 1
            try:
                status = status_fetcher(
                    registry.base_dir,
                    binding,
                    timeout_secs=timeout_secs,
                )
            except (AuthorityConfigurationError, OSError):
                failed += 1
                continue
            if status.state == "ready":
                ready += 1
            else:
                failed += 1
    return RenewalResult(attempted=attempted, ready=ready, failed=failed)


def _write_receipt(path: Path, result: RenewalResult) -> None:
    path.parent.mkdir(parents=True, exist_ok=True)
    payload = {
        "schema": 1,
        "checked_at": datetime.now(UTC).isoformat().replace("+00:00", "Z"),
        "attempted": result.attempted,
        "ready": result.ready,
        "failed": result.failed,
    }
    with tempfile.NamedTemporaryFile(
        "w", encoding="utf-8", dir=path.parent, delete=False
    ) as handle:
        json.dump(payload, handle, separators=(",", ":"), sort_keys=True)
        handle.write("\n")
        temporary = Path(handle.name)
    os.replace(temporary, path)


def main(argv: list[str] | None = None) -> int:
    parser = argparse.ArgumentParser(
        description="Renew active local Systray Gateway grants without provider traffic."
    )
    parser.add_argument("--receipt", type=Path)
    parser.add_argument("--timeout", type=float, default=DEFAULT_TIMEOUT_SECONDS)
    args = parser.parse_args(argv)
    result = renew_active_gateway_grants(timeout_secs=max(0.1, args.timeout))
    if args.receipt is not None:
        _write_receipt(args.receipt, result)
    print(
        f"gateway-grant-renewal: attempted={result.attempted} "
        f"ready={result.ready} failed={result.failed}"
    )
    return 0 if result.failed == 0 else 1


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