"""Authentication manager — API Key + per-message HMAC signing.

Implements the dual-layer auth described in Section 6 of the architecture doc:
  Layer 1: API Key in WebSocket handshake header
  Layer 2: Per-message HMAC-SHA256 signing with timestamp + nonce
  Layer 3: TLS transport (handled by the connection layer)
"""

from __future__ import annotations

import hashlib
import hmac
import time
import uuid
from typing import Any

from qremotex.config import ExecutorConfig


class AuthManager:
    """Handles API-key auth headers and per-message HMAC signing."""

    def __init__(self, config: ExecutorConfig) -> None:
        self._api_key = config.api_key
        self._key_id = config.parse_api_key_id()
        self._secret = config.api_key.encode("utf-8")

    @property
    def key_id(self) -> str:
        return self._key_id

    # ------------------------------------------------------------------ #
    # Layer 1 — Handshake headers
    # ------------------------------------------------------------------ #
    def handshake_params(self) -> dict[str, str]:
        """Query parameters for the WebSocket handshake URL."""
        return {"key_id": self._key_id}

    def handshake_headers(self) -> dict[str, str]:
        """HTTP headers included in the WebSocket upgrade request."""
        ts = str(int(time.time()))
        nonce = uuid.uuid4().hex
        payload = f"{ts}.{nonce}.{self._key_id}"
        sig = self._compute_hmac(payload)
        return {
            "X-QRP-Signature": f"sha256={sig}",
            "X-QRP-Timestamp": ts,
            "X-QRP-Nonce": nonce,
        }

    # ------------------------------------------------------------------ #
    # Layer 2 — Per-message signing
    # ------------------------------------------------------------------ #
    def sign_message(self, message_body: str) -> dict[str, str]:
        """Return HMAC headers for an outbound message.

        Signature payload: ``{timestamp}.{nonce}.{message_body}``
        """
        ts = str(int(time.time()))
        nonce = uuid.uuid4().hex
        payload = f"{ts}.{nonce}.{message_body}"
        sig = self._compute_hmac(payload)
        return {
            "X-QRP-Signature": f"sha256={sig}",
            "X-QRP-Timestamp": ts,
            "X-QRP-Nonce": nonce,
        }

    def sign_dict(self, msg: dict[str, Any]) -> dict[str, Any]:
        """Attach HMAC signature fields directly into a message dict.

        This is used when the transport embeds the signature inside the JSON
        payload (common in JSON-over-WebSocket protocols where you can't set
        per-frame HTTP headers).
        """
        import json

        body = json.dumps(msg, ensure_ascii=False, separators=(",", ":"))
        headers = self.sign_message(body)
        msg["_hmac_signature"] = headers["X-QRP-Signature"]
        msg["_hmac_timestamp"] = headers["X-QRP-Timestamp"]
        msg["_hmac_nonce"] = headers["X-QRP-Nonce"]
        return msg

    # ------------------------------------------------------------------ #
    # Internal
    # ------------------------------------------------------------------ #
    def _compute_hmac(self, payload: str) -> str:
        return hmac.new(self._secret, payload.encode("utf-8"), hashlib.sha256).hexdigest()
