"""Unified webhook signature verification."""

from __future__ import annotations

import hashlib
import hmac
import json
import time as _time

from primitif._exceptions import InvalidSignature


def verify_webhook(
    *,
    secret: str,
    signature: str,
    body: str | bytes,
    timestamp: str | None = None,
    tolerance: int = 300,
) -> dict:
    """Verify a webhook payload and return the parsed data.

    Works for both Mail webhooks (with timestamp) and Approval webhooks
    (without). Uses HMAC-SHA256 with timing-safe comparison.

    Args:
        secret: The webhook signing secret (from ``WebhookCreated.secret``
            or the Primitif console).
        signature: Value of the signature header (``X-Webhook-Signature``).
            May optionally include a ``sha256=`` prefix.
        body: Raw request body (str or bytes).
        timestamp: Value of the timestamp header (unix seconds). Required
            for Mail webhooks, optional for Approval webhooks.
        tolerance: Max age in seconds. Defaults to 300 (5 min). Only
            checked when ``timestamp`` is provided. Set to 0 to disable
            replay protection.

    Returns:
        Parsed JSON payload as a dict.

    Raises:
        InvalidSignature: If the signature does not match, the timestamp
            is missing/malformed, or the payload is too old.

    Example:
        >>> from primitif import verify_webhook
        >>> event = verify_webhook(
        ...     secret="whsec_abc123...",
        ...     signature=request.headers["X-Webhook-Signature"],
        ...     body=request.data,
        ...     timestamp=request.headers.get("X-Webhook-Timestamp"),
        ... )
        >>> print(event["type"], event["data"])
    """
    if not signature:
        raise InvalidSignature("Missing signature")
    if isinstance(body, bytes):
        body = body.decode("utf-8")

    # Replay protection (only when timestamp provided)
    if timestamp is not None and tolerance > 0:
        try:
            ts = int(timestamp)
        except (ValueError, TypeError):
            raise InvalidSignature("Invalid timestamp") from None
        if abs(_time.time() - ts) > tolerance:
            raise InvalidSignature("Timestamp too old")

    # Build the signed message
    if timestamp is not None:
        message = f"{timestamp}.{body}"
    else:
        message = body

    expected = hmac.new(
        secret.encode(), message.encode(), hashlib.sha256
    ).hexdigest()

    # Strip sha256= prefix if present
    sig = signature.removeprefix("sha256=")

    if not hmac.compare_digest(expected, sig):
        raise InvalidSignature("Signature mismatch")

    return json.loads(body)
