"""Integration tests for the Python SDK WebhookVerifier and WebhookEventType."""

import hashlib
import hmac
import json
import time

import pytest

from zyndpay import WebhookEventType, WebhookVerifier

SECRET = "whsec_test_signing_secret"


def build_signature(body: str, secret: str, timestamp: int = None) -> str:
    ts = timestamp if timestamp is not None else int(time.time())
    signed_payload = f"{ts}.{body}"
    digest = hmac.new(
        secret.encode("utf-8"),
        signed_payload.encode("utf-8"),
        hashlib.sha256,
    ).hexdigest()
    return f"t={ts},v1={digest}"


PAYIN_EVENT = json.dumps({
    "event": "payin.confirmed",
    "data": {"transactionId": "txn_123", "amount": "100", "status": "CONFIRMED"},
    "createdAt": "2024-01-01T00:00:00.000Z",
})


# ─── WebhookVerifier.verify() ─────────────────────────────────────────────────

def test_verify_valid_signature():
    verifier = WebhookVerifier(SECRET)
    sig = build_signature(PAYIN_EVENT, SECRET)
    event = verifier.verify(PAYIN_EVENT, sig)

    assert event["event"] == "payin.confirmed"
    assert event["data"]["transactionId"] == "txn_123"


def test_verify_raises_on_missing_signature():
    verifier = WebhookVerifier(SECRET)
    with pytest.raises(ValueError, match="Missing webhook signature header"):
        verifier.verify(PAYIN_EVENT, "")


def test_verify_raises_on_invalid_format():
    verifier = WebhookVerifier(SECRET)
    with pytest.raises(ValueError, match="Invalid webhook signature format"):
        verifier.verify(PAYIN_EVENT, "not-a-valid-sig")


def test_verify_raises_on_wrong_secret():
    verifier = WebhookVerifier(SECRET)
    sig = build_signature(PAYIN_EVENT, "wrong_secret")
    with pytest.raises(ValueError, match="Webhook signature verification failed"):
        verifier.verify(PAYIN_EVENT, sig)


def test_verify_raises_on_tampered_body():
    verifier = WebhookVerifier(SECRET)
    sig = build_signature(PAYIN_EVENT, SECRET)
    tampered = PAYIN_EVENT.replace("payin.confirmed", "payin.overpaid")
    with pytest.raises(ValueError, match="Webhook signature verification failed"):
        verifier.verify(tampered, sig)


def test_verify_raises_when_timestamp_too_old():
    verifier = WebhookVerifier(SECRET)
    stale_ts = int(time.time()) - 400  # 400s ago, default tolerance is 300s
    sig = build_signature(PAYIN_EVENT, SECRET, timestamp=stale_ts)
    with pytest.raises(ValueError, match="Webhook timestamp too old"):
        verifier.verify(PAYIN_EVENT, sig)


def test_verify_accepts_stale_timestamp_with_higher_tolerance():
    verifier = WebhookVerifier(SECRET)
    stale_ts = int(time.time()) - 400
    sig = build_signature(PAYIN_EVENT, SECRET, timestamp=stale_ts)
    event = verifier.verify(PAYIN_EVENT, sig, tolerance_seconds=600)
    assert event["event"] == "payin.confirmed"


# ─── WebhookEventType constants ───────────────────────────────────────────────

def test_event_type_constants_match_expected_strings():
    assert WebhookEventType.PAYIN_CONFIRMED == "payin.confirmed"
    assert WebhookEventType.PAYIN_OVERPAID == "payin.overpaid"
    assert WebhookEventType.PAYIN_UNDERPAID == "payin.underpaid"
    assert WebhookEventType.DEPOSIT_CONFIRMED == "deposit.confirmed"
    assert WebhookEventType.DEPOSIT_OVERPAID == "deposit.overpaid"
    assert WebhookEventType.DEPOSIT_UNDERPAID == "deposit.underpaid"
    assert WebhookEventType.PAYOUT_BROADCAST == "payout.broadcast"
    assert WebhookEventType.PAYOUT_CONFIRMED == "payout.confirmed"
    assert WebhookEventType.PAYOUT_FAILED == "payout.failed"
    assert WebhookEventType.WITHDRAWAL_BROADCAST == "withdrawal.broadcast"
    assert WebhookEventType.WITHDRAWAL_CONFIRMED == "withdrawal.confirmed"
    assert WebhookEventType.WITHDRAWAL_FAILED == "withdrawal.failed"


def test_webhook_verifier_header_name():
    assert WebhookVerifier.HEADER_NAME == "x-zyndpay-signature"
