"""Helpers para tu receptor; no inicia un servidor ni procesa mensajes.

verify_test_ping autentica exclusivamente pruebas sintéticas con tu verify token.
Para mensajes/estados usá la API de verificación de WhatsAut, o verify_signature
sólo cuando administrás la app Meta y disponés de su App Secret.
"""

import hashlib
import hmac
import json
import re
from datetime import UTC, datetime


def verify_challenge(
    mode: str | None,
    token: str | None,
    challenge: str | None,
    expected_token: str,
) -> str | None:
    """Retorna texto para HTTP 200, o None para rechazar con HTTP 403."""
    if mode != "subscribe" or not token or not challenge or not expected_token:
        return None
    if not hmac.compare_digest(token.encode("utf-8"), expected_token.encode("utf-8")):
        return None
    return challenge


def verify_signature(raw_body: bytes, signature: str | None, app_secret: str) -> bool:
    """Valida bytes originales. Firma ausente, inválida o secreto vacío: rechazo."""
    if not app_secret or signature is None:
        return False
    if re.fullmatch(r"sha256=[0-9a-fA-F]{64}", signature) is None:
        return False
    expected = hmac.new(app_secret.encode("utf-8"), raw_body, hashlib.sha256).hexdigest()
    return hmac.compare_digest(expected, signature[7:].lower())


def verify_test_ping(
    raw_body: bytes,
    signature: str | None,
    verify_token: str,
    callback_url: str,
    *,
    now: datetime | None = None,
) -> bool:
    """Sólo pruebas recientes para la URL exacta del panel; nunca autoriza mensajes.

    Usá X-WhatsAut-Test-Signature-256. Deduplificá request_id durante cinco
    minutos antes de cualquier efecto adicional; una prueba sólo recibe HTTP 2xx.
    """
    if not verify_token or not callback_url or not signature or len(raw_body) > 65536:
        return False
    if re.fullmatch(r"v1=[0-9a-f]{64}", signature) is None:
        return False
    material = b"whatsaut.webhook_test.v1\n" + callback_url.encode("utf-8") + b"\n" + raw_body
    expected = hmac.new(verify_token.encode("utf-8"), material, hashlib.sha256).hexdigest()
    if not hmac.compare_digest(expected, signature[3:]):
        return False
    try:
        body: object = json.loads(raw_body)
        if not isinstance(body, dict) or set(body) != {"object", "event", "request_id", "sent_at", "test"}:
            return False
        if body["object"] != "whatsaut_webhook_test" or body["event"] != "whatsaut.webhook_test" or body["test"] is not True:
            return False
        if not isinstance(body["request_id"], str) or re.fullmatch(r"[A-Za-z0-9_-]{8,80}", body["request_id"]) is None:
            return False
        if not isinstance(body["sent_at"], str):
            return False
        sent_at = datetime.fromisoformat(body["sent_at"])
        current = now or datetime.now(UTC)
        if sent_at.tzinfo is None or current.tzinfo is None:
            return False
        age = (current - sent_at).total_seconds()
        return -30 <= age <= 300
    except (ValueError, UnicodeDecodeError, RecursionError, OverflowError):
        return False
