import hashlib
import hmac
import json
from typing import Any, Dict, Optional

import requests


CRYPTOPAY_API_BASE = "https://pay.crypt.bot/api"


class CryptoPayError(RuntimeError):
    pass


def _request(token: str, method: str, params: Dict[str, Any]) -> Dict[str, Any]:
    if not token:
        raise CryptoPayError("CRYPTOPAY_TOKEN is empty")

    url = f"{CRYPTOPAY_API_BASE}/{method}"
    headers = {
        "Crypto-Pay-API-Token": token,
        "Content-Type": "application/json",
    }

    try:
        resp = requests.post(url, headers=headers, data=json.dumps(params), timeout=20)
    except Exception as e:
        raise CryptoPayError(f"CryptoPay request failed: {e}") from e

    try:
        data = resp.json()
    except Exception:
        raise CryptoPayError(f"CryptoPay returned non-JSON: {resp.status_code} {resp.text[:200]}")

    if not data.get("ok"):
        raise CryptoPayError(f"CryptoPay error: {data}")

    return data["result"]


def create_fiat_invoice_rub(
    token: str,
    amount_rub: float,
    description: str,
    payload: Optional[str] = None,
    paid_btn_name: str = "viewItem",
    paid_btn_url: Optional[str] = None,
) -> Dict[str, Any]:
    """Create a RUB fiat invoice. User can pay with supported crypto assets inside @CryptoBot.

    Docs: createInvoice.
    """
    params: Dict[str, Any] = {
        "currency_type": "fiat",
        "fiat": "RUB",
        "amount": f"{amount_rub:.2f}",
        "description": description,
        "paid_btn_name": paid_btn_name,
    }
    if payload:
        params["payload"] = payload
    if paid_btn_url:
        params["paid_btn_url"] = paid_btn_url

    return _request(token, "createInvoice", params)


def get_invoice_by_id(token: str, invoice_id: int) -> Optional[Dict[str, Any]]:
    res = _request(token, "getInvoices", {"invoice_ids": str(invoice_id)})
    items = res.get("items") if isinstance(res, dict) else None
    if not items:
        return None
    return items[0]


def verify_webhook_signature(app_token: str, raw_body: bytes, signature_hex: str) -> bool:
    """Verify Crypto Pay API webhook signature.

    Signature is HMAC-SHA-256 over the *raw* request body (unparsed JSON string),
    with secret key = SHA256(app_token).
    """
    if not app_token or not signature_hex:
        return False

    secret = hashlib.sha256(app_token.encode("utf-8")).digest()
    calc = hmac.new(secret, raw_body, hashlib.sha256).hexdigest()
    return hmac.compare_digest(calc, signature_hex)
