"""受控发布监控指标的 HMAC 认证。"""

from __future__ import annotations

import hashlib
import hmac
import json
import os
import time
from typing import Any

RELEASE_MONITOR_SECRET_ENV = "AGENT_RELEASE_MONITOR_SECRET"
MAX_CLOCK_SKEW_SECONDS = 300


class ReleaseMonitorConfigurationError(RuntimeError):
    """发布监控认证尚未完成安全配置。"""


class ReleaseMonitorAuthenticationError(PermissionError):
    """发布监控签名不可信。"""


def build_release_monitor_signature(
    *,
    timestamp: str,
    tenant_id: str,
    asset_id: str,
    release_id: str,
    stage: str,
    payload: dict[str, Any],
    secret: str | None = None,
) -> str:
    signing_secret = _resolve_secret(secret)
    message = _signature_message(
        timestamp=timestamp,
        tenant_id=tenant_id,
        asset_id=asset_id,
        release_id=release_id,
        stage=stage,
        payload=payload,
    )
    return hmac.new(
        signing_secret.encode("utf-8"),
        message.encode("utf-8"),
        hashlib.sha256,
    ).hexdigest()


def require_release_monitor_signature(
    *,
    timestamp: str | None,
    signature: str | None,
    tenant_id: str,
    asset_id: str,
    release_id: str,
    stage: str,
    payload: dict[str, Any],
    now_epoch_seconds: int | None = None,
) -> None:
    normalized_timestamp = str(timestamp or "").strip()
    normalized_signature = str(signature or "").strip().lower()
    if not normalized_timestamp or not normalized_signature:
        raise ReleaseMonitorAuthenticationError("发布评测缺少监控签名或时间戳。")
    try:
        parsed_timestamp = int(normalized_timestamp)
    except (TypeError, ValueError, OverflowError) as exc:
        raise ReleaseMonitorAuthenticationError("发布评测时间戳格式无效。") from exc
    now = int(time.time()) if now_epoch_seconds is None else int(now_epoch_seconds)
    if abs(now - parsed_timestamp) > MAX_CLOCK_SKEW_SECONDS:
        raise ReleaseMonitorAuthenticationError("发布评测签名已过期或服务器时钟偏差过大。")
    expected = build_release_monitor_signature(
        timestamp=normalized_timestamp,
        tenant_id=tenant_id,
        asset_id=asset_id,
        release_id=release_id,
        stage=stage,
        payload=payload,
    )
    if not hmac.compare_digest(normalized_signature, expected):
        raise ReleaseMonitorAuthenticationError("发布评测监控签名无效。")


def _signature_message(
    *,
    timestamp: str,
    tenant_id: str,
    asset_id: str,
    release_id: str,
    stage: str,
    payload: dict[str, Any],
) -> str:
    canonical_payload = json.dumps(
        payload,
        ensure_ascii=False,
        sort_keys=True,
        separators=(",", ":"),
        default=str,
    )
    payload_hash = hashlib.sha256(canonical_payload.encode("utf-8")).hexdigest()
    return "\n".join(
        (
            str(timestamp).strip(),
            str(tenant_id).strip(),
            str(asset_id).strip(),
            str(release_id).strip(),
            str(stage).strip(),
            payload_hash,
        )
    )


def _resolve_secret(value: str | None) -> str:
    secret = str(value if value is not None else os.environ.get(RELEASE_MONITOR_SECRET_ENV, ""))
    if len(secret.encode("utf-8")) < 32:
        raise ReleaseMonitorConfigurationError(
            f"{RELEASE_MONITOR_SECRET_ENV} 必须配置为至少 32 字节的独立密钥。"
        )
    return secret
