"""Клиент Crypto Pay API (@CryptoBot)."""

from __future__ import annotations

import hashlib
import hmac
import json
from typing import Optional

import aiohttp

from config import CRYPTO_PAY_API, CRYPTO_PAY_TOKEN


def _token() -> str:
    token = (CRYPTO_PAY_TOKEN or "").strip()
    if not token:
        raise RuntimeError("Не задан CRYPTO_PAY_TOKEN")
    return token


def verify_webhook_signature(body: bytes, signature: str) -> bool:
    secret = hashlib.sha256(_token().encode("utf-8")).digest()
    calc = hmac.new(secret, body, hashlib.sha256).hexdigest()
    got = (signature or "").strip().lower()
    return bool(got) and hmac.compare_digest(calc, got)


async def crypto_call(method: str, payload: Optional[dict] = None):
    url = f"{CRYPTO_PAY_API.rstrip('/')}/{method}"
    headers = {
        "Crypto-Pay-API-Token": _token(),
        "Content-Type": "application/json",
        "Accept": "application/json",
    }
    async with aiohttp.ClientSession() as session:
        async with session.post(url, json=payload or {}, headers=headers, timeout=aiohttp.ClientTimeout(total=30)) as response:
            raw = await response.text()
    try:
        data = json.loads(raw) if raw else {}
    except json.JSONDecodeError as exc:
        raise RuntimeError("Crypto Pay вернул не JSON") from exc
    if not data.get("ok"):
        err = data.get("error") or {}
        name = err.get("name") if isinstance(err, dict) else err
        raise RuntimeError(str(name or "Ошибка Crypto Pay"))
    result = data.get("result")
    if not isinstance(result, dict) and not isinstance(result, list):
        return {}
    return result


async def create_invoice(*, amount_usd: float, owner_tg_id: int) -> dict:
    amount = f"{float(amount_usd):.2f}"
    result = await crypto_call("createInvoice", {
        "currency_type": "fiat",
        "fiat": "USD",
        "amount": amount,
        "accepted_assets": "USDT,TON,BTC,ETH",
        "description": f"Пополнение баланса ловца на ${amount}",
        "hidden_message": f"Зачислено ${amount}",
        "payload": str(int(owner_tg_id)),
        "expires_in": 3600,
        "allow_comments": False,
        "allow_anonymous": False,
    })
    return result if isinstance(result, dict) else {}


async def get_invoices(invoice_ids: list[int]) -> list[dict]:
    if not invoice_ids:
        return []
    ids = ",".join(str(int(item)) for item in invoice_ids)
    result = await crypto_call("getInvoices", {"invoice_ids": ids})
    if isinstance(result, dict):
        items = result.get("items") or result.get("invoices") or []
        return items if isinstance(items, list) else []
    return result if isinstance(result, list) else []
