"""Immutable registered-customer Telegram route for weekly reminders."""

from __future__ import annotations

import hashlib
import hmac
import json
import os
from dataclasses import dataclass, field
from typing import Final

from .customer_coaching import CustomerRuntime
from .weekly_operations import (
    CustomerIdentityDigest,
    CustomerKey,
    WeeklyOperationsConflict,
    customer_identity_digest,
)

_ROUTE_SECRET: Final = os.urandom(32)


@dataclass(frozen=True, slots=True)
class _BoundRouteSeal:
    chat_id: str
    topic_id: str | None
    canonical_bytes: bytes
    digest: str
    customer: CustomerIdentityDigest
    signature: str

    def __post_init__(self) -> None:
        if not hmac.compare_digest(
            self.signature,
            _signature(
                self.chat_id,
                self.topic_id,
                self.canonical_bytes,
                self.digest,
                self.customer,
            ),
        ):
            raise WeeklyOperationsConflict("weekly reminder route is not registry-bound")


def _signature(
    chat_id: str,
    topic_id: str | None,
    canonical_bytes: bytes,
    digest: str,
    customer: CustomerIdentityDigest,
) -> str:
    values = (chat_id, topic_id or "", canonical_bytes.hex(), digest, customer)
    return hmac.new(_ROUTE_SECRET, "\0".join(values).encode(), hashlib.sha256).hexdigest()

@dataclass(frozen=True, slots=True)
class BoundWeeklyReminderRoute:
    """Route bytes that cannot be changed with dataclass replacement."""

    customer_identity_digest: CustomerIdentityDigest
    _seal: _BoundRouteSeal = field(repr=False, compare=False)

    def __post_init__(self) -> None:
        self._seal.__post_init__()
        if self.customer_identity_digest != self._seal.customer:
            raise WeeklyOperationsConflict("weekly reminder route customer drift")
        expected = _digest_route(self._seal.chat_id, self._seal.topic_id)
        if expected != (self._seal.canonical_bytes, self._seal.digest):
            raise WeeklyOperationsConflict("weekly reminder route bytes drift")

    @property
    def chat_id(self) -> str:
        return self._seal.chat_id

    @property
    def topic_id(self) -> str | None:
        return self._seal.topic_id

    @property
    def canonical_bytes(self) -> bytes:
        return self._seal.canonical_bytes

    @property
    def digest(self) -> str:
        return self._seal.digest

    def verify(self) -> None:
        self.__post_init__()


def _digest_route(chat_id: str, topic_id: str | None) -> tuple[bytes, str]:
    encoded = json.dumps(
        {"chat_id": chat_id, "topic_id": topic_id},
        sort_keys=True,
        separators=(",", ":"),
    ).encode()
    return encoded, hashlib.sha256(encoded).hexdigest()


def bind_registered_weekly_reminder_route(
    runtime: CustomerRuntime,
) -> BoundWeeklyReminderRoute:
    """Resolve route only from the sealed registered runtime."""
    identity = customer_identity_digest(CustomerKey(runtime.spec.customer_key))
    route = runtime.spec.telegram
    if not route.chat_id.strip():
        raise WeeklyOperationsConflict("weekly reminder registered route is incomplete")
    encoded, digest = _digest_route(route.chat_id, route.topic_id)
    seal = _BoundRouteSeal(
        route.chat_id,
        route.topic_id,
        encoded,
        digest,
        identity,
        _signature(route.chat_id, route.topic_id, encoded, digest, identity),
    )
    return BoundWeeklyReminderRoute(identity, seal)
