from __future__ import annotations

import asyncio
from collections.abc import Awaitable, Callable
from datetime import date

from checkin_cli.nutrition_onboarding_contract import QUESTION_FIELDS

from gateway.platforms.nutrition_onboarding_reconciliation import (
    NutritionOnboardingReconciler,
)
from gateway.platforms.telegram_nutrition_onboarding_copy import parse_answer
from gateway.platforms.telegram_nutrition_onboarding_preview_completion import (
    build_preview_completion,
    replace_answer,
)
from gateway.platforms.telegram_nutrition_onboarding_preview_publication import (
    TelegramNutritionOnboardingPreviewPublicationMixin,
)
from gateway.platforms.telegram_nutrition_onboarding_preview_types import (
    PreviewRoute,
    PreviewSession,
    route_key,
)
class TelegramNutritionOnboardingPreviewFlowMixin(
    TelegramNutritionOnboardingPreviewPublicationMixin
):
    _route_supplier: Callable[[], PreviewRoute | None]
    _sender: Callable[
        [PreviewRoute, str, bool, str | None, str | None],
        Awaitable[object],
    ]
    _reconciler: NutritionOnboardingReconciler
    _lock: asyncio.Lock
    _session: PreviewSession | None
    _consumed_message_ids: set[str]
    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
    def _arm_expiry(self) -> None:
        raise NotImplementedError
    async def _publish_question(
        self,
        message: object,
        route: PreviewRoute,
        cursor: int,
        answers: tuple[tuple[str, object], ...],
    ) -> None:
        raise NotImplementedError
    async def handle_text(self, message: object) -> bool:
        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
            if session is None:
                return True
            if route_key(message) != (
                route.user_id,
                route.chat_id,
                route.topic_id,
            ):
                return True
            incoming_id = str(getattr(message, "message_id", "") or "")
            if not incoming_id or incoming_id in self._consumed_message_ids:
                return True
            reply_to = getattr(message, "reply_to_message", None)
            if reply_to is None:
                return True
            reply_id = str(getattr(reply_to, "message_id", "") or "")
            if reply_id != session.expected_message_id:
                return True
            if session.phase == "confirming":
                return True
            field = (
                session.clarifications[session.clarification_cursor].field
                if session.phase == "clarifying"
                else QUESTION_FIELDS[session.cursor]
            )
            try:
                parsed = parse_answer(
                    field,
                    str(getattr(message, "text", "")),
                )
            except (TypeError, ValueError):
                await self._send_notice(
                    message,
                    route,
                    "입력 형식을 확인해 주세요. 기존 질문 메시지에 다시 답장해 주세요.",
                )
                return True
            self._consumed_message_ids.add(incoming_id)
            if session.phase == "clarifying":
                await self._advance_clarification(
                    message,
                    route,
                    session,
                    field,
                    parsed,
                )
                return True
            next_cursor = session.cursor + 1
            answers = (*session.answers, (field, parsed))
            if next_cursor == len(QUESTION_FIELDS):
                await self._finish_answers(
                    message,
                    route,
                    answers=answers,
                    allow_clarifications=True,
                )
                return True
            await self._publish_question(
                message,
                route,
                next_cursor,
                answers,
            )
        return True
    async def _advance_clarification(
        self,
        message: object,
        route: PreviewRoute,
        session: PreviewSession,
        field: str,
        parsed: object,
    ) -> None:
        answers = replace_answer(session.answers, field=field, value=parsed)
        cursor = session.clarification_cursor + 1
        if cursor < len(session.clarifications):
            await self._publish_clarification(
                message,
                route,
                answers,
                session.clarifications,
                cursor,
            )
            return
        await self._finish_answers(
            message,
            route,
            answers,
            allow_clarifications=False,
        )
    async def _finish_answers(
        self,
        message: object,
        route: PreviewRoute,
        answers: tuple[tuple[str, object], ...],
        *,
        allow_clarifications: bool,
        reference_date: date | None = None,
    ) -> None:
        session = self._session
        if reference_date is None:
            if session is None:
                raise RuntimeError("preview reference date is unavailable")
            reference_date = session.reference_date
        completion = await build_preview_completion(
            reconciler=self._reconciler,
            answers=answers,
            allow_clarifications=allow_clarifications,
            reference_date=reference_date,
        )
        if completion.phase == "failed":
            self.purge()
            await self._send_notice(message, route, completion.text)
        elif completion.phase == "clarifying":
            await self._publish_clarification(
                message,
                route,
                answers,
                completion.clarifications,
                0,
                reference_date=reference_date,
            )
        else:
            await self._publish_summary(
                message,
                route,
                completion.text,
                reference_date=reference_date,
            )
