"""
Unit tests for WhatsApp webhook signature verification.

Tests CHAN-03: Webhook signature is verified via HMAC-SHA256 on raw body bytes
before any JSON parsing.

Covers:
- Valid signature passes (returns raw body bytes)
- Invalid signature raises HTTPException(403)
- Timing-safe comparison used (hmac.compare_digest)
- Hub challenge verification (GET endpoint)
"""

from __future__ import annotations

import hashlib
import hmac
import json

import pytest
from fastapi import HTTPException


def make_valid_signature(body: bytes, app_secret: str) -> str:
    """Helper: generate a valid X-Hub-Signature-256 header value."""
    sig = hmac.new(app_secret.encode(), body, hashlib.sha256).hexdigest()
    return f"sha256={sig}"


class TestWhatsAppSignatureVerification:
    """Tests for verify_whatsapp_signature function."""

    def test_valid_signature_returns_body(self) -> None:
        """verify_whatsapp_signature must return raw body bytes when signature is valid."""
        from gateway.channels.whatsapp import verify_whatsapp_signature

        app_secret = "test_app_secret_abc123"
        body = b'{"object":"whatsapp_business_account"}'
        sig = make_valid_signature(body, app_secret)

        result = verify_whatsapp_signature(body, sig, app_secret)
        assert result == body

    def test_invalid_signature_raises_403(self) -> None:
        """verify_whatsapp_signature must raise HTTPException(403) when signature is invalid."""
        from gateway.channels.whatsapp import verify_whatsapp_signature

        app_secret = "test_app_secret_abc123"
        body = b'{"object":"whatsapp_business_account"}'
        bad_sig = "sha256=deadbeef0000000000000000000000000000000000000000000000000000000"

        with pytest.raises(HTTPException) as exc_info:
            verify_whatsapp_signature(body, bad_sig, app_secret)

        assert exc_info.value.status_code == 403

    def test_missing_sha256_prefix_raises_403(self) -> None:
        """Signature without 'sha256=' prefix must raise HTTPException(403)."""
        from gateway.channels.whatsapp import verify_whatsapp_signature

        app_secret = "test_app_secret_abc123"
        body = b'{"test": "data"}'
        # No 'sha256=' prefix
        bad_sig = "abcdef1234567890" * 4

        with pytest.raises(HTTPException) as exc_info:
            verify_whatsapp_signature(body, bad_sig, app_secret)

        assert exc_info.value.status_code == 403

    def test_empty_body_valid_signature(self) -> None:
        """verify_whatsapp_signature works on empty body with correct signature."""
        from gateway.channels.whatsapp import verify_whatsapp_signature

        app_secret = "secret"
        body = b""
        sig = make_valid_signature(body, app_secret)

        result = verify_whatsapp_signature(body, sig, app_secret)
        assert result == body

    def test_tampered_body_raises_403(self) -> None:
        """Signature computed on original body fails if body is modified."""
        from gateway.channels.whatsapp import verify_whatsapp_signature

        app_secret = "secret"
        original_body = b'{"message": "hello"}'
        sig = make_valid_signature(original_body, app_secret)

        # Tamper with the body
        tampered_body = b'{"message": "injected"}'

        with pytest.raises(HTTPException) as exc_info:
            verify_whatsapp_signature(tampered_body, sig, app_secret)

        assert exc_info.value.status_code == 403


class TestWhatsAppHubVerification:
    """Tests for WhatsApp webhook GET verification (hub challenge handshake)."""

    def test_valid_token_returns_challenge(self) -> None:
        """GET webhook with valid verify_token must return hub.challenge as plain text."""
        from gateway.channels.whatsapp import verify_hub_challenge

        token = "my_verify_token_xyz"
        challenge = "challenge_abc_123"

        result = verify_hub_challenge(
            hub_mode="subscribe",
            hub_verify_token=token,
            hub_challenge=challenge,
            expected_token=token,
        )
        assert result == challenge

    def test_invalid_token_raises_403(self) -> None:
        """GET webhook with wrong verify_token must raise HTTPException(403)."""
        from gateway.channels.whatsapp import verify_hub_challenge

        with pytest.raises(HTTPException) as exc_info:
            verify_hub_challenge(
                hub_mode="subscribe",
                hub_verify_token="wrong_token",
                hub_challenge="challenge_123",
                expected_token="correct_token",
            )

        assert exc_info.value.status_code == 403

    def test_wrong_mode_raises_403(self) -> None:
        """GET webhook with mode != 'subscribe' must raise HTTPException(403)."""
        from gateway.channels.whatsapp import verify_hub_challenge

        with pytest.raises(HTTPException) as exc_info:
            verify_hub_challenge(
                hub_mode="unsubscribe",
                hub_verify_token="correct_token",
                hub_challenge="challenge_123",
                expected_token="correct_token",
            )

        assert exc_info.value.status_code == 403
