"""Typed disposable facades over inherited production Telegram handlers."""

from __future__ import annotations

from collections.abc import Sequence
from datetime import datetime
from typing import Protocol, final

from telegram import Bot, InlineKeyboardMarkup, Message

from gateway.config import PlatformConfig
from gateway.platforms.nutrition_draft_callback_route import (
    NutritionDraftCallbackDenied,
)

from gateway.platforms.nutrition_coaching import (
    DraftAction,
    IncomingAddress,
    NutritionCoachingCoordinator,
)
from gateway.platforms.nutrition_weekly_dispatcher import (
    WeeklyOperationsCoordinator,
    WeeklyOperationsTask,
)
from gateway.platforms.nutrition_weekly_operations_publication_contract import (
    Topic59ProviderDelivered,
    Topic59ProviderFailure,
    Topic59ProviderKnownFailure,
    Topic59ProviderOutcome,
    Topic59ProviderUnknown,
)
from gateway.platforms.telegram import TelegramAdapter
from gateway.platforms.telegram_edit_transport import (
    TelegramEditDelivered,
    TelegramEditKnownFailure,
    TelegramEditOutcome,

    TelegramEditUnknownReason,
)
from scripts.nutricoach_v140_fake_telegram import (
    KnownProviderFailure,
    ProviderTimeout,
    UnknownProviderFailure,
)

from scripts.nutricoach_v140_fake_telegram_updates import (
    FakeCallbackQuery,
    FakeMessage,
)


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


class FacadeProviderMessageError(TypeError):
    """Production returned a non-message send receipt."""


class FacadeMarkupError(TypeError):
    """Production returned a markup outside its declared Telegram contract."""


class DisposableWeeklyTelegramAdapter(TelegramAdapter):
    """Expose only the inherited weekly tick and Topic-59 transport seams."""

    def __init__(
        self,
        config: PlatformConfig,
        bot: Bot,
        candidate_digest: str,
    ) -> None:
        super().__init__(config, weekly_reminder_customers=())
        self._bot: Bot = bot
        self._task26_candidate_digest: str = candidate_digest

    async def _tick_handler_seam(
        self,
        coordinator: WeeklyOperationsCoordinator,
        tasks: Sequence[WeeklyOperationsTask],
        now: datetime,
    ) -> tuple[str, ...]:
        return await super()._dispatch_weekly_operations_tick(
            coordinator, tasks, local_now=now,
        )

    async def run_weekly_tick(
        self,
        coordinator: WeeklyOperationsCoordinator,
        tasks: Sequence[WeeklyOperationsTask],
        now: datetime,
    ) -> tuple[str, ...]:
        """Invoke the inherited production weekly tick handler."""
        return await self._tick_handler_seam(coordinator, tasks, now)

    async def _send_handler_seam(
        self, chat_id: str, topic_id: str, text: str,
    ) -> TelegramProviderMessage:
        result = await super()._send_nutrition_topic(
            chat_id=chat_id, topic_id=topic_id, text=text,
        )
        if not isinstance(result, Message):
            raise FacadeProviderMessageError("strict-topic send returned no message")
        return result

    async def _edit_handler_seam(
        self, chat_id: str, message_id: str, text: str,
    ) -> TelegramEditOutcome:
        return await super().edit_message_outcome(chat_id, message_id, text)

    async def send_topic59(
        self, chat_id: str, topic_id: str, text: str,
    ) -> Topic59ProviderOutcome:
        """Invoke the inherited strict-topic send implementation."""
        try:
            result = await self._send_handler_seam(chat_id, topic_id, text)
            return Topic59ProviderDelivered(
                self._nutrition_delivery_receipt(result)
            )
        except KnownProviderFailure:
            return Topic59ProviderKnownFailure(Topic59ProviderFailure.REJECTED)
        except ProviderTimeout:
            return Topic59ProviderUnknown(Topic59ProviderFailure.TIMEOUT)
        except UnknownProviderFailure:
            return Topic59ProviderUnknown(Topic59ProviderFailure.CONNECTION_LOST)

    async def edit_topic59(
        self, chat_id: str, topic_id: str, message_id: str, text: str,
    ) -> Topic59ProviderOutcome:
        """Invoke the inherited Telegram edit implementation."""
        if topic_id != "59":
            return Topic59ProviderKnownFailure(Topic59ProviderFailure.REJECTED)
        outcome = await self._edit_handler_seam(chat_id, message_id, text)
        if isinstance(outcome, TelegramEditDelivered):
            return Topic59ProviderDelivered(outcome.message_id)
        if isinstance(outcome, TelegramEditKnownFailure):
            return Topic59ProviderKnownFailure(Topic59ProviderFailure.REJECTED)
        reason = (
            Topic59ProviderFailure.TIMEOUT
            if outcome.reason is TelegramEditUnknownReason.TIMEOUT
            else Topic59ProviderFailure.CONNECTION_LOST
        )
        return Topic59ProviderUnknown(reason)


@final
class Topic59TransportFacade:
    """Adapt public disposable methods to the production transport protocol."""

    def __init__(self, adapter: DisposableWeeklyTelegramAdapter) -> None:
        self._adapter = adapter

    async def send(self, *, chat_id: str, topic_id: str, text: str) -> Topic59ProviderOutcome:
        return await self._adapter.send_topic59(chat_id, topic_id, text)

    async def edit(
        self, *, chat_id: str, topic_id: str, message_id: str, text: str,
    ) -> Topic59ProviderOutcome:
        return await self._adapter.edit_topic59(chat_id, topic_id, message_id, text)


class DisposableOwnerTelegramAdapter(TelegramAdapter):
    """Expose inherited owner callback/text/send behavior to one scenario."""

    def __init__(
        self,
        config: PlatformConfig,
        bot: Bot,
        coordinator: NutritionCoachingCoordinator,
    ) -> None:
        super().__init__(config, weekly_reminder_customers=())
        self._bot: Bot = bot
        self._scenario_bot: Bot = bot
        self._nutrition_coaching: NutritionCoachingCoordinator = coordinator

    def daily_privacy_regression_control(self, action: DraftAction) -> str:
        """Expose the legacy raw projection only as a sentinel test control."""
        return super()._nutrition_checkin_review_summary(action)

    async def publish_owner_card(
        self, owner: IncomingAddress, action: DraftAction,
    ) -> str:
        """Send then activate controls with inherited rendering and transport."""
        sent = await self._send_nutrition_topic(
            chat_id=owner.chat_id, topic_id=owner.topic_id,
            text=self._nutrition_draft_text(action),
        )
        message_id = self._nutrition_delivery_receipt(sent)
        render_identity = format(int(message_id), "x")
        markup = self._nutrition_draft_markup(
            action, render_identity=render_identity,
        )
        if markup is not None and not isinstance(markup, InlineKeyboardMarkup):
            raise FacadeMarkupError("owner card markup type is invalid")
        _ = await self._scenario_bot.edit_message_text(
            chat_id=int(owner.chat_id), message_id=int(message_id),
            text=self._nutrition_draft_text(action), reply_markup=markup,
        )
        return message_id

    async def _callback_handler_seam(
        self, query: FakeCallbackQuery,
    ) -> NutritionDraftCallbackDenied | None:
        return await super()._handle_nutrition_draft_callback(
            query, query.data, query.message,
        )

    async def _text_handler_seam(
        self,
        message: FakeMessage,
        owner: IncomingAddress,
        coordinator: NutritionCoachingCoordinator,
    ) -> bool:
        return await super()._handle_nutrition_draft_edit_text(
            message, owner, coordinator,
        )

    async def handle_owner_callback(
        self, query: FakeCallbackQuery,
    ) -> NutritionDraftCallbackDenied | None:
        """Invoke the inherited production callback handler."""
        return await self._callback_handler_seam(query)

    async def handle_owner_text(
        self,
        message: FakeMessage,
        owner: IncomingAddress,
        coordinator: NutritionCoachingCoordinator,
    ) -> bool:
        """Invoke the inherited production owner text handler."""
        return await self._text_handler_seam(message, owner, coordinator)


