"""OpenRouter key provisioning and account utilities."""

from __future__ import annotations

import logging

import httpx

logger = logging.getLogger(__name__)

OR_BASE = "https://openrouter.ai/api/v1"


def provision_key(admin_key: str, label: str, limit_usd: float) -> str:
    """Create a sub-key with a spend cap via the OpenRouter admin API.

    Args:
        admin_key: Your OpenRouter admin/management key (OR_ADMIN_KEY).
        label: A human-readable name for the key (shown in your OR dashboard).
        limit_usd: Hard spend cap in USD. OpenRouter will reject requests beyond this.

    Returns:
        The provisioned API key string.

    Raises:
        httpx.HTTPStatusError: If the API call fails.
        RuntimeError: If the response is missing the key field.
    """
    key, _ = provision_key_full(admin_key, label, limit_usd)
    return key


def provision_key_full(admin_key: str, label: str, limit_usd: float) -> tuple[str, str]:
    """Create a sub-key and return ``(api_key, key_hash)``.

    The ``key_hash`` is needed for :func:`delete_key`. If you only need
    the API key, use :func:`provision_key` instead.
    """
    resp = httpx.post(
        f"{OR_BASE}/keys",
        headers={
            "Authorization": f"Bearer {admin_key}",
            "Content-Type": "application/json",
        },
        json={"name": label, "limit": limit_usd},
        timeout=15.0,
    )
    resp.raise_for_status()
    data = resp.json()
    key = data.get("key") or data.get("data", {}).get("key", "")
    key_hash = data.get("data", {}).get("hash", "")
    if not key:
        raise RuntimeError(f"provision_key: no key in response: {data}")
    logger.info("Provisioned sub-key %s… (limit $%.2f)", key[:12], limit_usd)
    return key, key_hash


def get_usage(api_key: str) -> float | None:
    """Return current usage in USD for a sub-key, or None on error.

    Uses the OpenRouter /auth/key endpoint which returns the key's lifetime usage.
    Poll this periodically to track spend against a provisioned key's limit.
    """
    try:
        resp = httpx.get(
            f"{OR_BASE}/auth/key",
            headers={"Authorization": f"Bearer {api_key}"},
            timeout=10.0,
        )
        if resp.status_code != 200:
            return None
        return resp.json().get("data", {}).get("usage", 0.0)
    except Exception:
        return None


def get_account_balance(api_key: str) -> tuple[float | None, float | None, float | None]:
    """Return (balance, total_credits, total_usage) for the account.

    Returns (None, None, None) on any error.

    The balance is total_credits minus total_usage — the amount you can still spend.
    """
    try:
        resp = httpx.get(
            f"{OR_BASE}/credits",
            headers={"Authorization": f"Bearer {api_key}"},
            timeout=10.0,
        )
        if resp.status_code != 200:
            return None, None, None
        data = resp.json().get("data", {})
        total = float(data.get("total_credits", 0))
        used = float(data.get("total_usage", 0))
        return total - used, total, used
    except Exception:
        return None, None, None


def get_available_models(api_key: str) -> dict[str, dict] | None:
    """Return {model_id: model_info} from OpenRouter /models.

    Each value contains at minimum a "pricing" dict with "prompt" and "completion"
    keys (cost per token, multiply by 1_000_000 for per-million price).

    Returns:
        A mapping of model ID -> model info on success.
        An empty dict if the API succeeds but returns no models.
        None on request / HTTP failure.
    """
    try:
        resp = httpx.get(
            f"{OR_BASE}/models",
            headers={"Authorization": f"Bearer {api_key}"},
            timeout=15.0,
        )
        resp.raise_for_status()
        models = resp.json().get("data", [])
        return {m["id"]: m for m in models}
    except Exception:
        return None


def get_available_models_or_empty(api_key: str) -> dict[str, dict]:
    """Return {model_id: model_info} from OpenRouter /models, or ``{}`` on error."""
    return get_available_models(api_key) or {}


def delete_key(admin_key: str, key_hash: str) -> bool:
    """Delete a sub-key from OpenRouter by its key hash.

    Use the ``key_hash`` returned by :func:`provision_key_full`.

    Args:
        admin_key: Your OpenRouter admin/management key (OR_ADMIN_KEY).
        key_hash: The key's hash (from the provisioning response ``data.hash``).

    Returns:
        True if deletion succeeded, False on error.
    """
    try:
        resp = httpx.delete(
            f"{OR_BASE}/keys/{key_hash}",
            headers={"Authorization": f"Bearer {admin_key}"},
            timeout=15.0,
        )
        resp.raise_for_status()
        logger.info("Deleted sub-key hash=%s…", key_hash[:12])
        return True
    except Exception as e:
        logger.warning("Failed to delete sub-key hash=%s: %s", key_hash[:12], e)
        return False
