"""
FastPayGlobal Python SDK v1.0.0
Requires: Python 3.8+, requests
    pip install requests
"""
from __future__ import annotations
import hmac, hashlib, time, json
from typing import Any, Callable, Optional
import requests


class FastPayGlobalError(Exception):
    def __init__(self, code: str, message: str):
        super().__init__(message)
        self.code = code


class FastPayGlobal:
    def __init__(
        self,
        public_key: str = "",
        secret_key: str = "",
        webhook_secret: str = "",
        base_url: str = "https://demo.fastpayglobal.app",
    ):
        self.public_key = public_key
        self.secret_key = secret_key
        self.webhook_secret = webhook_secret
        self.base_url = base_url.rstrip("/")

    def _req(self, method: str, path: str, body: Optional[dict] = None, use_public_key: bool = False) -> dict:
        headers = {"Accept": "application/json"}
        if body is not None:
            headers["Content-Type"] = "application/json"
        if use_public_key:
            headers["X-Public-Key"] = self.public_key
        if self.secret_key:
            headers["X-Secret-Key"] = self.secret_key
        try:
            r = requests.request(method, self.base_url + path, headers=headers,
                                 data=json.dumps(body) if body is not None else None, timeout=30)
        except requests.RequestException as e:
            raise FastPayGlobalError("network_error", str(e))
        try:
            data = r.json()
        except ValueError:
            data = {}
        if r.status_code >= 400:
            raise FastPayGlobalError(f"api_error_{r.status_code}", data.get("error", f"HTTP {r.status_code}"))
        return data

    def create_payment(self, *, amount: float, order_id: str, currency: str = "BDT",
                       reference: Optional[str] = None, customer: Optional[dict] = None,
                       metadata: Optional[dict] = None) -> dict:
        return self._req("POST", "/api/public/create-payment", {
            "amount": amount, "currency": currency, "orderId": order_id,
            "reference": reference, "customer": customer, "metadata": metadata,
        }, use_public_key=True)

    def get_payment(self, payment_id: str) -> dict:
        return self._req("GET", f"/api/public/payment/{payment_id}")

    def verify_payment(self, payment_id: str, trx_id: str, sender: Optional[str] = None) -> dict:
        return self._req("POST", "/api/public/verify-payment",
                         {"paymentId": payment_id, "trxId": trx_id, "sender": sender},
                         use_public_key=True)

    def verify_webhook(self, raw_body: str | bytes, signature: str) -> bool:
        if not self.webhook_secret:
            return False
        body = raw_body.encode() if isinstance(raw_body, str) else raw_body
        expected = hmac.new(self.webhook_secret.encode(), body, hashlib.sha256).hexdigest()
        return hmac.compare_digest(expected, signature)

    def poll_until_final(self, payment_id: str, *, interval: float = 3.0,
                         timeout: float = 15 * 60, on_update: Optional[Callable[[dict], None]] = None) -> dict:
        start = time.time()
        while time.time() - start < timeout:
            p = self.get_payment(payment_id)
            if on_update:
                on_update(p)
            if p.get("status") in {"paid", "expired", "failed", "cancelled"}:
                return p
            time.sleep(interval)
        raise FastPayGlobalError("timeout", "Polling timed out")


# Deprecated alias kept for older integrations.
PaysolutionError = FastPayGlobalError
