"""Public service contracts for nutrition onboarding."""

from __future__ import annotations

import hashlib
import json
from collections.abc import Mapping
from typing import ClassVar, Final

from pydantic import BaseModel, ConfigDict

from checkin_cli.nutrition_onboarding_models import OnboardingState


QUESTION_FIELDS = (
    "date_of_birth",
    "equation_sex_basis",
    "height_cm",
    "weight_kg",
    "activity_category",
    "activity_rationale",
    "goal_type",
    "target_weight_kg",
    "target_date",
    "allergies",
    "intolerances",
    "religious_ethical_exclusions",
    "disliked_foods",
    "dietary_preferences",
    "conditions",
    "medications",
    "pregnancy_breastfeeding",
    "eating_disorder_risk",
    "cooking_access",
    "budget_band",
    "meal_count",
    "schedule_constraints",
)
CUSTOMER_QUESTIONNAIRE_V2: Final = "customer_v2"
CUSTOMER_V2_SCREENS: Final = (
    "goal_type",
    "target_weight_kg",
    "target_date",
    "meal_count",
    "activity_profile",
    "food_preferences_profile",
    "lifestyle_profile",
    "allergies",
    "intolerances",
    "date_of_birth",
    "equation_sex_basis",
    "height_cm",
    "weight_kg",
    "conditions",
    "medications",
    "pregnancy_breastfeeding",
    "eating_disorder_risk",
)
CUSTOMER_V2_SCREEN_FIELDS: Final = {
    "activity_profile": ("activity_category", "activity_rationale"),
    "food_preferences_profile": (
        "religious_ethical_exclusions",
        "disliked_foods",
        "dietary_preferences",
    ),
    "lifestyle_profile": (
        "cooking_access",
        "budget_band",
        "schedule_constraints",
    ),
}


def questionnaire_screens(
    questionnaire_version: str | None,
    answers: Mapping[str, object],
) -> tuple[str, ...]:
    """Return the versioned customer-visible screen sequence."""
    if questionnaire_version is None:
        return QUESTION_FIELDS
    if questionnaire_version != CUSTOMER_QUESTIONNAIRE_V2:
        raise ValueError("unsupported questionnaire version")
    if answers.get("goal_type") == "maintain":
        return tuple(
            screen
            for screen in CUSTOMER_V2_SCREENS
            if screen not in {"target_weight_kg", "target_date"}
        )
    return CUSTOMER_V2_SCREENS


def canonical_fields_for_screen(
    questionnaire_version: str | None,
    screen: str,
) -> tuple[str, ...]:
    """Expand one visible screen to its canonical answer fields."""
    if questionnaire_version is None:
        if screen not in QUESTION_FIELDS:
            raise ValueError("unknown legacy question field")
        return (screen,)
    if questionnaire_version != CUSTOMER_QUESTIONNAIRE_V2:
        raise ValueError("unsupported questionnaire version")
    if screen not in CUSTOMER_V2_SCREENS:
        raise ValueError("unknown customer questionnaire screen")
    return CUSTOMER_V2_SCREEN_FIELDS.get(screen, (screen,))


def screen_for_canonical_field(
    questionnaire_version: str | None,
    field: str,
) -> str:
    """Return the owning visible screen for one canonical field."""
    if questionnaire_version is None:
        if field not in QUESTION_FIELDS:
            raise ValueError("unknown legacy question field")
        return field
    for screen in CUSTOMER_V2_SCREENS:
        if field in canonical_fields_for_screen(questionnaire_version, screen):
            return screen
    raise ValueError("canonical field has no customer questionnaire screen")


class DomainModel(BaseModel):
    model_config: ClassVar[ConfigDict] = ConfigDict(extra="forbid", frozen=True)


class OnboardingAuthority(DomainModel):
    customer_key: str
    customer_user_id: int
    customer_chat_id: int
    customer_topic_id: int
    owner_user_id: int
    owner_chat_id: int
    owner_topic_id: int
    consent_notice_version: str
    consent_granted: bool
    customer_enabled: bool


class MessageEvidence(DomainModel):
    actor_user_id: int
    chat_id: int
    topic_id: int
    message_id: int
    update_id: int


class OnboardingStatus(DomainModel):
    customer_key: str
    state: OnboardingState
    answer_count: int
    next_field: str | None
    questionnaire_version: str | None
    question_number: int
    question_total: int
    previous_cursor: int | None
    baseline_digest: str | None = None
    owner_reviewed: bool = False
    help_field: str | None = None
    answer_failure_count: int = 0


def canonical_digest(value: object) -> str:
    return hashlib.sha256(
        json.dumps(value, ensure_ascii=False, sort_keys=True, separators=(",", ":")).encode()
    ).hexdigest()


def example_answer(field: str) -> object:
    examples: dict[str, object] = {
        "date_of_birth": "1996-08-01",
        "equation_sex_basis": "male",
        "height_cm": "180",
        "weight_kg": "80",
        "activity_category": "moderate",
        "activity_rationale": "주 3회 근력 운동",
        "goal_type": "maintain",
        "target_weight_kg": None,
        "target_date": None,
        "pregnancy_breastfeeding": False,
        "eating_disorder_risk": False,
        "cooking_access": "기본 조리 가능",
        "budget_band": "보통",
        "meal_count": 3,
        "schedule_constraints": "없음",
    }
    structured = {
        "allergies",
        "intolerances",
        "religious_ethical_exclusions",
        "disliked_foods",
        "dietary_preferences",
        "conditions",
        "medications",
    }
    if field in structured:
        return {"status": "none", "items": []}
    if field not in examples:
        raise ValueError(f"unknown question field: {field}")
    return examples[field]
