"""Unified tracker auth primitives (ADR-0017, alpha issues 01/02/20).

Two mechanisms live here:

- **Hive peer HMAC** — gossip mutation endpoints require a signature computed
  as HMAC-SHA256(hive_secret, "<timestamp>." + raw_body). All trackers in a
  hive share one secret (``--hive-secret`` / MESHNET_HIVE_SECRET). Timestamps
  outside the skew window are rejected to blunt replay.
- **Validator service token** — a dedicated bearer credential distinct from
  client API keys and admin sessions (``--validator-service-token`` /
  MESHNET_VALIDATOR_SERVICE_TOKEN), resolved to the ``validator`` role.

Role resolution itself happens in the request handler (it needs the account
store); these are the shared, dependency-free pieces.
"""

from __future__ import annotations

import hmac
import hashlib
import time

HIVE_SIGNATURE_HEADER = "X-Meshnet-Hive-Signature"
HIVE_TIMESTAMP_HEADER = "X-Meshnet-Hive-Timestamp"
HIVE_MAX_CLOCK_SKEW_SECONDS = 300.0


def _hive_digest(secret: str, timestamp: str, body: bytes) -> str:
    return hmac.new(
        secret.encode(), timestamp.encode() + b"." + body, hashlib.sha256
    ).hexdigest()


def sign_hive_request(secret: str, body: bytes, *, timestamp: float | None = None) -> dict[str, str]:
    """Headers a tracker attaches when pushing gossip to a hive peer."""
    ts = f"{timestamp if timestamp is not None else time.time():.3f}"
    return {
        HIVE_SIGNATURE_HEADER: _hive_digest(secret, ts, body),
        HIVE_TIMESTAMP_HEADER: ts,
    }


def verify_hive_request(
    secret: str | None,
    headers,
    body: bytes,
    *,
    now: float | None = None,
) -> bool:
    """True only when the request carries a fresh, valid hive signature.

    Fails closed: no configured secret means no gossip is accepted.
    """
    if not secret:
        return False
    signature = headers.get(HIVE_SIGNATURE_HEADER)
    timestamp = headers.get(HIVE_TIMESTAMP_HEADER)
    if not signature or not timestamp:
        return False
    try:
        ts_value = float(timestamp)
    except ValueError:
        return False
    current = now if now is not None else time.time()
    if abs(current - ts_value) > HIVE_MAX_CLOCK_SKEW_SECONDS:
        return False
    return hmac.compare_digest(signature, _hive_digest(secret, timestamp, body))


def is_validator_token(token: str | None, configured: str | None) -> bool:
    """Constant-time check of a presented bearer token against the configured
    validator service token."""
    if not token or not configured:
        return False
    return hmac.compare_digest(token, configured)
