from __future__ import annotations

import time
from datetime import datetime

from account_registry import Account
from grok_oauth import GrokOAuthAuthError, GrokOAuthError, GrokOAuthSession, GrokOAuthTransportError
from health_client import AccountSnapshot, HealthStatus


class GrokHealthClient:
    """Health + monthly billing usage for Grok accounts.

    Maps monthly used/limit → secondary_used_pct only (no 5h/primary window).
    """

    def fetch(self, account: Account, timeout_secs: float = 10.0) -> AccountSnapshot:
        checked_at = time.time()
        auth_path = account.account_home / "auth.json"
        if not auth_path.is_file():
            return AccountSnapshot(
                status=HealthStatus.BROKEN,
                primary_used_pct=None,
                secondary_used_pct=None,
                checked_at=checked_at,
                detail="missing auth.json",
            )

        session = GrokOAuthSession(auth_path, timeout_secs=timeout_secs)
        try:
            billing = session.get_billing()
        except GrokOAuthAuthError:
            return AccountSnapshot(
                status=HealthStatus.BROKEN,
                primary_used_pct=None,
                secondary_used_pct=None,
                checked_at=checked_at,
                detail="authentication required",
            )
        except (GrokOAuthTransportError, GrokOAuthError, OSError):
            return AccountSnapshot(
                status=HealthStatus.UNKNOWN,
                primary_used_pct=None,
                secondary_used_pct=None,
                checked_at=checked_at,
                detail="billing unavailable",
            )

        percent, reset_at = self._parse_billing(billing)
        return AccountSnapshot(
            status=HealthStatus.OK,
            primary_used_pct=None,
            secondary_used_pct=percent,
            primary_reset_at=None,
            secondary_reset_at=reset_at,
            checked_at=checked_at,
        )

    @staticmethod
    def _parse_billing(payload: dict) -> tuple[int | None, float | None]:
        config = payload.get("config")
        if not isinstance(config, dict):
            return None, None
        used_obj = config.get("used")
        limit_obj = config.get("monthlyLimit")
        used = used_obj.get("val") if isinstance(used_obj, dict) else None
        limit = limit_obj.get("val") if isinstance(limit_obj, dict) else None
        percent: int | None = None
        if isinstance(used, (int, float)) and isinstance(limit, (int, float)) and limit > 0:
            percent = int(min(100, max(0, round(100.0 * float(used) / float(limit)))))
        reset_raw = config.get("billingPeriodEnd")
        reset_at: float | None = None
        if isinstance(reset_raw, str):
            try:
                reset_at = datetime.fromisoformat(reset_raw.replace("Z", "+00:00")).timestamp()
            except ValueError:
                reset_at = None
        if reset_at is None:
            reset_at = None
        return percent, reset_at
