"""Airminal billing API client.

Handles check_balance and charge operations.
API key is NEVER logged — masked in all output.
"""

from __future__ import annotations

import logging
import math
from dataclasses import dataclass

import httpx

logger = logging.getLogger(__name__)


@dataclass
class BalanceResult:
    success: bool
    balance: float
    locked: float


@dataclass
class ChargeResult:
    success: bool
    charged: float
    balance_after: float
    error: str  # empty on success


class InsufficientTokensError(Exception):
    """Raised when org has insufficient balance for a charge."""


class AirminalClient:
    """REST client for airminal billing API."""

    def __init__(self, api_url: str, api_key: str) -> None:
        self._url = api_url.rstrip("/")
        # Key format in .env: "{api_key}_{secret_hash}" — API uses only the part before "_"
        self._key = api_key.split("_")[0] if "_" in api_key else api_key
        self._http = httpx.Client(timeout=15)

    def _auth_params(self) -> dict[str, str]:
        return {"api_key": self._key}

    def check_balance(self) -> BalanceResult:
        """GET balance for the authenticated org."""
        resp = self._http.get(self._url, params=self._auth_params())
        resp.raise_for_status()
        data = resp.json()
        return BalanceResult(
            success=bool(data.get("success")),
            balance=float(data.get("balance", 0)),
            locked=float(data.get("locked", 0)),
        )

    def charge(self, tokens: float, task: str, reference: str) -> ChargeResult:
        """POST a transactional charge.

        Returns ChargeResult on success.
        Raises InsufficientTokensError on 402.
        Raises httpx exceptions on other errors.
        """
        # Airminal API requires integer tokens — round up fractional amounts
        api_tokens = max(1, math.ceil(tokens))
        payload = {
            "tokens": api_tokens,
            "task": task,
            "reference": reference,
            "service_type": "agent_fb",
            "units": 1,
        }
        resp = self._http.post(
            self._url, params=self._auth_params(),
            json=payload, headers={"Content-Type": "application/json"},
        )

        if resp.status_code == 402:
            data = resp.json() if resp.headers.get("content-type", "").startswith("application/json") else {}
            raise InsufficientTokensError(
                data.get("error", "INSUFFICIENT_TOKENS")
            )

        resp.raise_for_status()
        data = resp.json()
        return ChargeResult(
            success=bool(data.get("success")),
            charged=float(data.get("charged", tokens)),
            balance_after=float(data.get("balance_after", 0)),
            error="",
        )

    def close(self) -> None:
        self._http.close()
