import hashlib
import hmac
import json
import time


class WebhookEventType:
    """
    All webhook event types emitted by the ZyndPay API.

    Your endpoint receives a POST with body:
    ``{"event": str, "data": dict, "createdAt": "ISO-8601"}``

    Verify the ``X-ZyndPay-Signature`` header before trusting the payload.

    Payin events (incoming payment state changes):
        - ``PAYIN_CONFIRMED``  — amount within ±0.5% of requested. Normal success.
        - ``PAYIN_OVERPAID``   — payer sent more than requested.
        - ``PAYIN_UNDERPAID``  — payer sent less than requested.

    Deposit events (wallet deposit state changes, no fee deducted):
        - ``DEPOSIT_CONFIRMED`` / ``DEPOSIT_OVERPAID`` / ``DEPOSIT_UNDERPAID``

    Payout events (outgoing payment state changes):
        - ``PAYOUT_BROADCAST``  — transaction submitted to TRON network.
        - ``PAYOUT_CONFIRMED``  — 20+ block confirmations. Funds delivered.
        - ``PAYOUT_FAILED``     — broadcast or confirmation failed.

    Withdrawal events (merchant withdrawal state changes):
        - ``WITHDRAWAL_BROADCAST``  — transaction submitted to TRON network.
        - ``WITHDRAWAL_CONFIRMED``  — 20+ block confirmations received.
        - ``WITHDRAWAL_FAILED``     — broadcast or confirmation failed.
    """

    PAYIN_CONFIRMED = "payin.confirmed"
    PAYIN_OVERPAID = "payin.overpaid"
    PAYIN_UNDERPAID = "payin.underpaid"

    DEPOSIT_CONFIRMED = "deposit.confirmed"
    DEPOSIT_OVERPAID = "deposit.overpaid"
    DEPOSIT_UNDERPAID = "deposit.underpaid"

    PAYOUT_BROADCAST = "payout.broadcast"
    PAYOUT_CONFIRMED = "payout.confirmed"
    PAYOUT_FAILED = "payout.failed"

    WITHDRAWAL_BROADCAST = "withdrawal.broadcast"
    WITHDRAWAL_CONFIRMED = "withdrawal.confirmed"
    WITHDRAWAL_FAILED = "withdrawal.failed"


class WebhookVerifier:
    """Verify ZyndPay webhook signatures."""

    HEADER_NAME = "x-zyndpay-signature"

    def __init__(self, signing_secret: str):
        self._secret = signing_secret

    def verify(self, payload: str, signature: str, tolerance_seconds: int = 300) -> dict:
        """
        Verify a webhook signature and parse the event payload.

        Args:
            payload: The raw request body (string)
            signature: The value of the X-ZyndPay-Signature header
            tolerance_seconds: Max age of the event in seconds (default: 300)

        Returns:
            Parsed webhook event dict with "type", "data", etc.

        Raises:
            ValueError: If the signature is invalid or the event is too old.

        Example::

            verifier = zyndpay.webhooks
            event = verifier.verify(request.data, request.headers["X-ZyndPay-Signature"])
            print(event["type"])  # "payin.confirmed"
        """
        if not signature:
            raise ValueError("Missing webhook signature header")

        parts = signature.split(",")
        t_part = next((p for p in parts if p.startswith("t=")), None)
        v1_part = next((p for p in parts if p.startswith("v1=")), None)

        if not t_part or not v1_part:
            raise ValueError('Invalid webhook signature format — expected "t=<timestamp>,v1=<hmac>"')

        timestamp = int(t_part.replace("t=", ""))
        received_hmac = v1_part.replace("v1=", "")

        now = int(time.time())
        if abs(now - timestamp) > tolerance_seconds:
            raise ValueError(
                f"Webhook timestamp too old ({abs(now - timestamp)}s > {tolerance_seconds}s tolerance)"
            )

        signed_payload = f"{timestamp}.{payload}"
        expected_hmac = hmac.new(
            self._secret.encode("utf-8"),
            signed_payload.encode("utf-8"),
            hashlib.sha256,
        ).hexdigest()

        if not hmac.compare_digest(expected_hmac, received_hmac):
            raise ValueError("Webhook signature verification failed")

        return json.loads(payload)
