"""Typed state and outcomes for the profile-local check-in wizard."""

from __future__ import annotations

from dataclasses import dataclass
from enum import StrEnum
from typing import Any

from pydantic import BaseModel, ConfigDict, Field

try:
    from checkin_cli.models import SafetyReason
except ImportError:  # Core contracts land alongside this module.
    SafetyReason = Any  # type: ignore[misc,assignment]


ADAPTIVE_FOLLOW_UP_IDS: tuple[str, ...] = (
    "Q-SLEEP-CAUSE", "Q-SLEEP-ADJUST",
    "Q-COND-SYMPTOM",
    "Q-COND-INTENSITY",
    "Q-PERF-REASON",
    "Q-PERF-NEXT",
)


class WizardFlow(StrEnum):
    """The independently finalizable wizard flows."""

    MORNING = "morning"
    WORKOUT = "workout"
    NUTRITION = "nutrition_daily"
    TRAINER_SESSION = "trainer_session"
    SCHEDULE_REFERENCE = "schedule_reference"


class WizardBranch(StrEnum):
    """Deterministic customer or trainer outcome branch."""

    NORMAL = "normal"
    ANOMALY = "anomaly"
    CHANGE = "change"
    SAFETY_HOLD = "safety_hold"


class WizardStatus(StrEnum):
    """Observable result states for a wizard transition."""

    ADVANCED = "advanced"
    SAVED = "saved"
    INVALID = "invalid"
    REJECTED = "rejected"
    SAFETY_STOP = "safety_stop"
    DEFERRED = "deferred"


@dataclass(frozen=True, slots=True)
class WizardContext:
    """The exact Telegram identity boundary supplied by the adapter."""

    owner_id: str
    topic_id: str
    customer_key: str | None = None


class WizardSession(BaseModel):
    """Durable private draft state; it never participates in trend views."""

    model_config = ConfigDict(frozen=True)

    session_id: str = Field(pattern=r"^[a-f0-9]{32}$")
    flow: WizardFlow
    owner_id: str = Field(min_length=1, max_length=256)
    customer_key: str | None = Field(default=None, min_length=1, max_length=64)
    topic_id: str = Field(min_length=1, max_length=256)
    kst_day: str = Field(pattern=r"^\d{4}-\d{2}-\d{2}$")
    version: int = Field(ge=0)
    step: str = Field(min_length=1, max_length=80)
    answers: dict[str, str] = Field(default_factory=dict)
    step_history: tuple[str, ...] = ()
    safety_signals: tuple[str, ...] = ()
    safety_reasons: tuple[SafetyReason, ...] = ()
    branch: WizardBranch | None = None
    follow_up_ids: tuple[str, ...] = ()
    supersedes: str | None = Field(default=None, max_length=128)
    finalized_event_id: str | None = Field(default=None, max_length=128)
    macro_order: str = Field(
        default="protein_carbohydrate_fat",
        pattern=r"^(protein_carbohydrate_fat|carbohydrate_protein_fat)$",
    )

    @property
    def safe_hold_reasons(self) -> tuple[SafetyReason, ...]:
        """Expose the canonical typed safety reasons under the adapter name."""
        return self.safety_reasons


@dataclass(frozen=True, slots=True)
class WizardResult:
    """Safe adapter-facing result without health values or callback payloads."""

    status: WizardStatus
    session_id: str
    version: int
    step: str
    message: str
    branch: WizardBranch | None = None
    follow_up_ids: tuple[str, ...] = ()
    safety_signals: tuple[str, ...] = ()
    safety_reasons: tuple[SafetyReason, ...] = ()
    position: int = 0
    total: int = 0
    can_previous: bool = False
    can_skip: bool = False

    @property
    def safe_hold_reasons(self) -> tuple[SafetyReason, ...]:
        """Expose the canonical typed safety reasons under the adapter name."""
        return self.safety_reasons
