"""TS-13 — property tests for the Svix HMAC verifier (sign -> verify round-trip).

The §5.5 property: for EVERY validly-signed payload, the verifier accepts and
returns the (id, ts); any tampered signature is rejected.
"""

from __future__ import annotations

import base64
import hashlib
import hmac

import pytest
from hypothesis import given, settings
from mgf.common.webhooks import decode_svix_secret
from tests.unit._strategies import event_ids, webhook_bodies

from mgf.fastapi.exceptions import HmacVerificationError
from mgf.fastapi.webhooks import HmacWebhookVerifier

pytestmark = [pytest.mark.property]

_SECRET = b"whsec_property_secret"
_TS = 1_700_000_000


def _sign(body: bytes, *, event_id: str, ts: int = _TS, secret: bytes = _SECRET) -> str:
    signed = f"{event_id}.{ts}.".encode() + body
    # Sign with the base64-decoded `whsec_` key (decode_svix_secret), as the
    # verifier now does via the shared mgf.common.webhooks primitive (0.49).
    return "v1," + base64.b64encode(
        hmac.new(decode_svix_secret(secret), signed, hashlib.sha256).digest()
    ).decode("ascii")


def _verifier() -> HmacWebhookVerifier:
    return HmacWebhookVerifier(secret=_SECRET, replay_window_seconds=300, now=lambda: float(_TS))


@given(body=webhook_bodies, event_id=event_ids)
@settings(max_examples=120)
def test_valid_signature_always_accepted(body: bytes, event_id: str) -> None:
    headers = {
        "svix-id": event_id,
        "svix-timestamp": str(_TS),
        "svix-signature": _sign(body, event_id=event_id),
    }
    # mgf-common 0.49.1 HMACs the RAW body bytes (matching Svix) — a correctly
    # signed body of ANY bytes (UTF-8 JSON or arbitrary binary) is accepted.
    got_id, got_ts = _verifier().verify(headers, body)
    assert got_id == event_id
    assert got_ts == _TS


@given(body=webhook_bodies, event_id=event_ids)
@settings(max_examples=120)
def test_tampered_signature_always_rejected(body: bytes, event_id: str) -> None:
    sig = _sign(body, event_id=event_id)
    # Flip the last base64 char -> a different (still well-formed) signature.
    tampered = sig[:-1] + ("A" if sig[-1] != "A" else "B")
    headers = {"svix-id": event_id, "svix-timestamp": str(_TS), "svix-signature": tampered}
    with pytest.raises(HmacVerificationError):
        _verifier().verify(headers, body)
