from __future__ import annotations

import asyncio
import logging
from collections.abc import Awaitable, Callable

from gateway.platforms.telegram_nutrition_onboarding_preview_types import (
    PreviewRoute,
    PreviewSession,
    route_key,
)


logger = logging.getLogger(__name__)


class TelegramNutritionOnboardingPreviewCallbackMixin:
    _route_supplier: Callable[[], PreviewRoute | None]
    _lock: asyncio.Lock
    _session: PreviewSession | None

    def reserves(self, message: object) -> bool:
        raise NotImplementedError

    def purge(self) -> None:
        raise NotImplementedError

    async def _send_notice(
        self,
        message: object,
        route: PreviewRoute,
        text: str,
    ) -> object | None:
        raise NotImplementedError

    async def handle_callback(self, query: object) -> bool:
        message = getattr(query, "message", None)
        if not self.reserves(message):
            return False
        route = self._route_supplier()
        if route is None:
            self.purge()
            return True
        async with self._lock:
            session = self._session
            actor = str(getattr(getattr(query, "from_user", None), "id", ""))
            message_id = str(getattr(message, "message_id", "") or "")
            valid = (
                session is not None
                and session.phase == "confirming"
                and str(getattr(query, "data", "")) == "npv:confirm"
                and actor == route.user_id
                and route_key(message)[1:] == (route.chat_id, route.topic_id)
                and message_id == session.expected_message_id
            )
            if not valid:
                await self._answer_stale_callback(query)
                return True
            self.purge()
            await self._retire_keyboard(query)
            answer = getattr(query, "answer", None)
            if callable(answer):
                await answer(text="입력 확인 미리보기를 완료했습니다.")
            await self._send_notice(
                message,
                route,
                (
                    "입력 확인이 저장되는 단계입니다.\n"
                    "[PREVIEW] 실제 저장은 하지 않았습니다.\n"
                    "실제 온보딩에서는 이제 운영자 검토로 넘어갑니다.\n"
                    "아직 영양 코칭은 시작되거나 활성화되지 않습니다."
                ),
            )
        return True

    @staticmethod
    async def _answer_stale_callback(query: object) -> None:
        answer = getattr(query, "answer", None)
        if callable(answer):
            await answer(text="이 카드는 이미 처리됐거나 사용할 수 없습니다.")

    @staticmethod
    async def _retire_keyboard(query: object) -> None:
        edit = getattr(query, "edit_message_reply_markup", None)
        if not callable(edit):
            return
        try:
            await edit(reply_markup=None)
        except Exception:
            logger.info(
                "Nutrition preview keyboard retirement failed",
                exc_info=True,
            )
