"""Typed Telegram send/edit outcomes used by the weekly host."""

from __future__ import annotations

from dataclasses import dataclass
from typing import TYPE_CHECKING, Never, Protocol, assert_never, final

from gateway.platforms.telegram_edit_transport import (
    TelegramEditDelivered,
    TelegramEditKnownFailure,
    TelegramEditKnownReason,
    TelegramEditOutcome,
    TelegramEditUnknown,
    edit_telegram_text,
)

if TYPE_CHECKING:
    from telegram import Message

    from gateway.platforms.nutrition_weekly_reminder import (
        TelegramReminderDelivered,
        TelegramReminderRejected,
    )
    from gateway.platforms.telegram_edit_transport import TelegramTextEditor


@dataclass(frozen=True, slots=True)
class ReminderNoSendRejection:
    """Provider result proving rejection before any send."""

    reason: str


@final
class ReminderNoSendRejected(RuntimeError):
    """Provider exception proving rejection before any send."""

    reason: str

    def __init__(self, reason: str) -> None:
        self.reason = reason
        super().__init__(reason)


class TelegramSendReceipt(Protocol):
    @property
    def message_id(self) -> int: ...


@dataclass(frozen=True, slots=True)
class TelegramNonfinalEdit:
    success: bool
    message_id: str | None = None
    error: str | None = None
    retryable: bool = False


def _edit_variant(value: TelegramEditOutcome) -> TelegramEditOutcome | str:
    return value


def _invalid_edit_outcome(value: str) -> Never:
    raise AssertionError(f"invalid Telegram edit outcome: {value!r}")


class TelegramWeeklyTransportMixin:
    """Classify weekly Telegram provider outcomes at one host boundary."""

    _bot: TelegramTextEditor | None = None

    async def _send_nutrition_topic(
        self, *, chat_id: str, topic_id: str | None, text: str,
    ) -> Message | TelegramSendReceipt:
        _ = chat_id, topic_id, text
        raise NotImplementedError

    @staticmethod
    def _nutrition_delivery_receipt(result: Message | TelegramSendReceipt) -> str:
        _ = result
        raise NotImplementedError

    @staticmethod
    def _reminder_no_send_rejection(
        reason_or_result: BaseException | Message | TelegramSendReceipt,
    ) -> str | None:
        _ = reason_or_result
        raise NotImplementedError

    async def edit_message_outcome(
        self, chat_id: str, message_id: str, content: str,
    ) -> TelegramEditOutcome:
        """Edit once through the typed provider classifier."""
        if self._bot is None:
            return TelegramEditKnownFailure(TelegramEditKnownReason.REJECTED)
        return await edit_telegram_text(
            self._bot, chat_id=chat_id, message_id=message_id, text=content,
        )

    async def _edit_nonfinal_message(
        self, chat_id: str, message_id: str, content: str,
    ) -> TelegramNonfinalEdit:
        outcome = await self.edit_message_outcome(chat_id, message_id, content)
        match _edit_variant(outcome):
            case TelegramEditDelivered(message_id=delivered_id):
                return TelegramNonfinalEdit(True, message_id=delivered_id)
            case TelegramEditUnknown(reason=reason):
                return TelegramNonfinalEdit(False, error=reason.value, retryable=True)
            case TelegramEditKnownFailure(reason=reason):
                return TelegramNonfinalEdit(False, error=reason.value)
            case unreachable:
                assert_never(_invalid_edit_outcome(unreachable))

    async def send_weekly_reminder(
        self, chat_id: str, topic_id: str | None, text: str,
    ) -> TelegramReminderDelivered | TelegramReminderRejected:
        """Adapt the existing Telegram send and audit receipt semantics."""
        from gateway.platforms.nutrition_weekly_reminder import (
            TelegramReminderDelivered,
            TelegramReminderRejected,
            reminder_provider_unknown,
        )
        try:
            result = await self._send_nutrition_topic(
                chat_id=chat_id, topic_id=topic_id, text=text,
            )
        except ReminderNoSendRejected as error:
            return TelegramReminderRejected(error.reason)
        except (TimeoutError, OSError) as error:
            raise reminder_provider_unknown() from error
        rejection = self._reminder_no_send_rejection(result)
        if rejection is not None:
            return TelegramReminderRejected(rejection)
        receipt = self._nutrition_delivery_receipt(result)
        return TelegramReminderDelivered(receipt, receipt)

    async def edit_weekly_topic59_outcome(
        self, chat_id: str, message_id: str, text: str,
    ) -> TelegramEditOutcome:
        """Edit the ledger-bound message through the shared classifier."""
        return await self.edit_message_outcome(chat_id, message_id, text)

