import hashlib
import hmac
import time

from payfence.hmac_verify import verify_signature

SECRET = "test-secret-key"


def _sign(method, path, timestamp, request_id, body):
    body_hash = hashlib.sha256(body.encode() if isinstance(body, str) else body).hexdigest()
    canonical = f"{method}\n{path}\n{timestamp}\n{request_id}\n{body_hash}"
    return hmac.new(SECRET.encode(), canonical.encode(), hashlib.sha256).hexdigest()


def _now():
    return str(int(time.time()))


class TestVerifySignature:
    def test_valid_signature(self):
        ts = _now()
        sig = _sign("POST", "/v1/weather", ts, "req-1", '{"city":"NYC"}')
        assert verify_signature(
            secret=SECRET, method="POST", path="/v1/weather",
            timestamp=ts, request_id="req-1", body='{"city":"NYC"}', signature=sig,
        ) is True

    def test_wrong_signature(self):
        ts = _now()
        assert verify_signature(
            secret=SECRET, method="POST", path="/v1/weather",
            timestamp=ts, request_id="req-1", body='{"city":"NYC"}', signature="bad",
        ) is False

    def test_expired_timestamp(self):
        ts = str(int(time.time()) - 600)
        sig = _sign("POST", "/v1/weather", ts, "req-1", '{"city":"NYC"}')
        assert verify_signature(
            secret=SECRET, method="POST", path="/v1/weather",
            timestamp=ts, request_id="req-1", body='{"city":"NYC"}', signature=sig,
        ) is False

    def test_invalid_timestamp(self):
        assert verify_signature(
            secret=SECRET, method="POST", path="/v1/weather",
            timestamp="not-a-number", request_id="req-1", body="", signature="x",
        ) is False

    def test_custom_tolerance(self):
        ts = str(int(time.time()) - 10)
        sig = _sign("GET", "/v1/data", ts, "req-2", "")
        # 5s tolerance → fail
        assert verify_signature(
            secret=SECRET, method="GET", path="/v1/data",
            timestamp=ts, request_id="req-2", body="", signature=sig,
            tolerance_seconds=5,
        ) is False
        # 15s tolerance → pass
        assert verify_signature(
            secret=SECRET, method="GET", path="/v1/data",
            timestamp=ts, request_id="req-2", body="", signature=sig,
            tolerance_seconds=15,
        ) is True

    def test_bytes_body(self):
        ts = _now()
        body = b'{"raw":true}'
        sig = _sign("POST", "/v1/data", ts, "req-3", body.decode())
        assert verify_signature(
            secret=SECRET, method="POST", path="/v1/data",
            timestamp=ts, request_id="req-3", body=body, signature=sig,
        ) is True

    def test_empty_signature(self):
        ts = _now()
        assert verify_signature(
            secret=SECRET, method="GET", path="/",
            timestamp=ts, request_id="req-4", body="", signature="",
        ) is False
