# Copyright (c) 2026 Nous Research
"""Configuration boundary for the NutriCoach channel inbox capability."""

from __future__ import annotations

import hashlib
import json
import re
from collections.abc import Mapping
from dataclasses import dataclass
from enum import StrEnum
from typing import ClassVar, Literal, override

from pydantic import (
    BaseModel,
    ConfigDict,
    Field,
    JsonValue,
    ValidationError,
    field_validator,
)

_DIGEST = re.compile(r"[a-f0-9]{64}")


class ChannelInboxConfigRejectReason(StrEnum):
    """Typed configuration rejection reasons."""

    NOT_AN_OBJECT = "not_an_object"
    PAYLOAD = "payload"


@dataclass(frozen=True, slots=True)
class ChannelInboxConfigError(ValueError):
    """A declared channel inbox capability is malformed."""

    reason: ChannelInboxConfigRejectReason

    @override
    def __str__(self) -> str:
        """Return the stable machine-consumed reason code.

        Returns:
            The rejection reason.

        """
        return self.reason.value


class ChannelInboxAuthorityError(RuntimeError):
    """Runtime authority cannot prove a safe channel delivery."""


@dataclass(frozen=True, slots=True)
class ChannelInboxAuthority:
    """Candidate-bound Telegram authority identity."""

    direct_messages_chat_id: str
    parent_channel_id: str
    bot_id: str
    candidate_digest: str


@dataclass(frozen=True, slots=True)
class ChannelInboxRuntimeAuthority:
    """Observed authority returned by the live Telegram runtime."""

    bot_id: int | str
    parent_channel_id: int | str
    candidate_digest: str
    can_manage_direct_messages: bool


@dataclass(frozen=True, slots=True)
class ChannelInboxConfig:
    """Candidate-bound opt-in configuration for one direct-messages chat."""

    enabled: bool
    authority: ChannelInboxAuthority
    capability_digest: str

    @classmethod
    def from_extra(
        cls,
        extra: Mapping[str, JsonValue],
    ) -> ChannelInboxConfig | None:
        """Parse the optional capability from trusted platform config.

        Returns:
            Parsed configuration, or ``None`` when the capability is absent.

        Raises:
            ChannelInboxConfigError: The declared configuration is malformed.

        """
        raw = extra.get("nutricoach_channel_inbox")
        if raw is None:
            return None
        if not isinstance(raw, Mapping):
            raise ChannelInboxConfigError(
                ChannelInboxConfigRejectReason.NOT_AN_OBJECT,
            )
        try:
            payload = _ChannelInboxPayload.model_validate(raw)
        except ValidationError as exc:
            raise ChannelInboxConfigError(
                ChannelInboxConfigRejectReason.PAYLOAD,
            ) from exc
        return cls(
            payload.enabled,
            ChannelInboxAuthority(
                payload.direct_messages_chat_id,
                payload.parent_channel_id,
                payload.bot_id,
                payload.candidate_digest,
            ),
            payload.capability_digest,
        )

    @property
    def direct_messages_chat_id(self) -> str:
        """Return the configured direct-messages chat ID."""
        return self.authority.direct_messages_chat_id

    @property
    def parent_channel_id(self) -> str:
        """Return the configured parent channel ID."""
        return self.authority.parent_channel_id

    @property
    def bot_id(self) -> str:
        """Return the configured bot ID."""
        return self.authority.bot_id

    @property
    def candidate_digest(self) -> str:
        """Return the loaded-candidate binding."""
        return self.authority.candidate_digest

    def matches_chat(self, chat_id: int | str) -> bool:
        """Return whether a Telegram chat is the exact configured inbox.

        Returns:
            ``True`` only for the configured direct-messages chat.

        """
        return str(chat_id).strip() == self.direct_messages_chat_id

    def runtime_authorized(
        self,
        runtime: ChannelInboxRuntimeAuthority,
    ) -> bool:
        """Verify the authenticated bot and loaded candidate.

        Returns:
            ``True`` only for the exact sealed runtime authority.

        """
        return (
            self.enabled
            and str(runtime.bot_id).strip() == self.bot_id
            and str(runtime.parent_channel_id).strip() == self.parent_channel_id
            and runtime.candidate_digest == self.candidate_digest
            and runtime.can_manage_direct_messages
            and self.capability_digest
            == channel_inbox_capability_digest(self.authority)
        )

    def runtime_matches(
        self,
        *,
        bot_id: int | str,
        parent_channel_id: int | str,
        candidate_digest: str,
        can_manage_direct_messages: bool,
    ) -> bool:
        """Verify primitive runtime observations without exposing SDK types."""
        return self.runtime_authorized(
            ChannelInboxRuntimeAuthority(
                bot_id=bot_id,
                parent_channel_id=parent_channel_id,
                candidate_digest=candidate_digest,
                can_manage_direct_messages=can_manage_direct_messages,
            )
        )


class _ChannelInboxPayload(BaseModel):
    model_config: ClassVar[ConfigDict] = ConfigDict(
        extra="forbid",
        frozen=True,
        strict=True,
    )

    schema_name: Literal["nutricoach-channel-inbox-v1"] = Field(alias="schema")
    enabled: bool
    direct_messages_chat_id: str
    parent_channel_id: str
    bot_id: str
    candidate_digest: str
    capability_digest: str

    @field_validator(
        "direct_messages_chat_id",
        "parent_channel_id",
        "bot_id",
    )
    @classmethod
    def _canonical_identifier(cls, value: str) -> str:
        normalized = value.strip()
        try:
            parsed = int(normalized)
        except ValueError as exc:
            raise ValueError from exc
        if parsed == 0 or normalized != str(parsed):
            raise ValueError
        return normalized

    @field_validator("candidate_digest", "capability_digest")
    @classmethod
    def _valid_digest(cls, value: str) -> str:
        if _DIGEST.fullmatch(value) is None:
            raise ValueError
        return value


def channel_inbox_capability_digest(
    authority: ChannelInboxAuthority,
) -> str:
    """Derive the candidate-bound capability identity.

    Returns:
        SHA-256 over canonical machine-consumed authority fields.

    """
    payload = {
        "bot_id": authority.bot_id,
        "candidate_digest": authority.candidate_digest,
        "direct_messages_chat_id": authority.direct_messages_chat_id,
        "parent_channel_id": authority.parent_channel_id,
        "schema": "nutricoach-channel-inbox-authority-v1",
    }
    canonical = json.dumps(
        payload,
        ensure_ascii=True,
        separators=(",", ":"),
        sort_keys=True,
    )
    return hashlib.sha256(canonical.encode("ascii")).hexdigest()
