"""Korean prompt copy and boundary parsing for nutrition onboarding."""

from __future__ import annotations

import re
from typing import Any

_MEASUREMENT_UNITS = {
    "height_cm": "cm",
    "weight_kg": "kg",
    "target_weight_kg": "kg",
}
_ACTIVITY_CATEGORIES = {
    "좌식": "sedentary",
    "가벼움": "light",
    "보통": "moderate",
    "매우 활동적": "very_active",
    "최고 활동": "extra_active",
}
_CLOSED_CHOICES = {
    "activity_category": _ACTIVITY_CATEGORIES,
    "equation_sex_basis": {
        "남성": "male",
        "여성": "female",
        "선택 안 함": "decline",
    },
    "goal_type": {
        "감량": "loss",
        "유지": "maintain",
        "증량": "gain",
    },
}
_UNAMBIGUOUS_CHOICE_QUALIFIERS = ("", " 수준")
_UNAMBIGUOUS_CHOICE_COPULAS = ("", "입니다", "이에요", "예요")
_KOREAN_MEAL_COUNTS = {
    "한": 1,
    "두": 2,
    "세": 3,
    "네": 4,
    "다섯": 5,
    "여섯": 6,
    "일곱": 7,
    "여덟": 8,
    "아홉": 9,
    "열": 10,
}
_STRUCTURED_NONE_ANSWERS = {
    "allergies": {"음식 알레르기는 없습니다."},
    "intolerances": {"음식 불내증은 없습니다."},
    "religious_ethical_exclusions": {
        "종교적 또는 윤리적으로 제외하는 음식은 없습니다."
    },
    "disliked_foods": {"싫어해서 피하는 음식은 없습니다."},
    "dietary_preferences": {"특별한 식단 선호는 없습니다."},
    "conditions": {"진단받은 질환은 없습니다."},
    "medications": {"복용 중인 약이나 보충제는 없습니다."},
}
_BOOLEAN_ANSWERS = {
    "예": True,
    "아니오": False,
    "확실하지 않음": None,
    "임신 또는 수유에 해당하지 않습니다.": False,
    "섭식장애 위험이나 과거력은 없습니다.": False,
}


def _parse_measurement(value: str, unit: str) -> str | None:
    if " 또는 " in value or " 혹은 " in value:
        return None
    matches = re.findall(rf"(?P<number>\d+(?:\.\d+)?)\s*{unit}", value.casefold())
    if len(matches) != 1:
        return None
    number = matches[0]
    return number.rstrip("0").rstrip(".") if "." in number else number


def _parse_meal_count(value: str) -> int:
    normalized = re.sub(r"^하루\s*", "", value.strip())
    numeric = re.fullmatch(r"(?P<count>\d+)\s*(?:끼|회)", normalized)
    if numeric:
        return int(numeric.group("count"))
    korean = re.fullmatch(
        rf"(?P<count>{'|'.join(_KOREAN_MEAL_COUNTS)})\s*(?:끼|회)",
        normalized,
    )
    if korean:
        return _KOREAN_MEAL_COUNTS[korean.group("count")]
    return int(normalized)


PROMPTS = {
    "date_of_birth": "생년월일을 YYYY-MM-DD 형식으로 입력해 주세요.",
    "equation_sex_basis": "계산 기준을 입력해 주세요: 남성 / 여성 / 선택 안 함",
    "height_cm": "키를 cm 단위 숫자로 입력해 주세요.",
    "weight_kg": "현재 체중을 kg 단위 숫자로 입력해 주세요.",
    "activity_category": "활동 수준: 좌식 / 가벼움 / 보통 / 매우 활동적 / 최고 활동",
    "activity_rationale": "주간 운동 횟수와 활동 근거를 적어 주세요.",
    "goal_type": "목표를 입력해 주세요: 감량 / 유지 / 증량",
    "target_weight_kg": "목표 체중을 kg으로 입력해 주세요. 유지라면 '없음'.",
    "target_date": "목표 날짜를 YYYY-MM-DD로 입력해 주세요. 유지라면 '없음'.",
    "allergies": "알레르기를 쉼표로 구분해 입력해 주세요. 없으면 '없음'.",
    "intolerances": "불내증을 쉼표로 구분해 입력해 주세요. 없으면 '없음'.",
    "religious_ethical_exclusions": "종교·윤리상 제외 식품을 입력해 주세요. 없으면 '없음'.",
    "disliked_foods": "싫어하는 식품을 입력해 주세요. 없으면 '없음'.",
    "dietary_preferences": "선호 식품을 입력해 주세요. 없으면 '없음'.",
    "conditions": "의학적 고려사항을 입력해 주세요. 없으면 '없음'.",
    "medications": "복용 약·보충제를 입력해 주세요. 없으면 '없음'.",
    "pregnancy_breastfeeding": "임신·수유 중인가요? 예 / 아니오 / 확실하지 않음",
    "eating_disorder_risk": "섭식장애 위험·과거력이 있나요? 예 / 아니오 / 확실하지 않음",
    "cooking_access": "사용 가능한 조리 환경을 적어 주세요.",
    "budget_band": "식비 범위를 적어 주세요.",
    "meal_count": "하루 식사 횟수를 2~6 숫자로 입력해 주세요.",
    "schedule_constraints": "식사 시간 제약을 적어 주세요. 없으면 '없음'.",
}


def card(status: Any) -> tuple[str, str | None, str]:
    if status.state.value == "collecting":
        return PROMPTS[status.next_field], None, "customer"
    if status.state.value == "customer_attestation":
        return "입력 요약이 준비됐습니다. 본인이 입력한 내용임을 확인해 주세요.", "attest", "customer"
    if status.state.value == "owner_review":
        return "고객 영양 기초정보의 운영자 검토가 필요합니다.", "owner_ok", "owner"
    if status.state.value == "safety_hold":
        return "외부 임상 검토가 필요해 온보딩이 보류됐습니다.", None, "owner"
    if status.state.value == "ready":
        return (
            "온보딩 자료와 준비 검증이 완료됐습니다. 운영자 활성화 전까지 고객 전달은 비활성 상태입니다.",
            None,
            "owner",
        )
    if status.state.value == "rejected":
        return (
            "온보딩 승인이 거절됐습니다. 고객 영양 코칭은 비활성 상태입니다.",
            None,
            "owner",
        )
    return "승인이 완료됐습니다. 안전 자료를 최종 생성하고 있습니다.", None, "owner"


def parse_legacy_activity_answer(
    value: object,
) -> tuple[str, str] | None:
    if not isinstance(value, str):
        return None
    for label, category in _ACTIVITY_CATEGORIES.items():
        marker = f"활동 수준: {label}. "
        if value.startswith(marker):
            rationale = value.removeprefix(marker).strip()
            if rationale:
                return category, rationale
    return None


def _parse_closed_choice(value: str, choices: dict[str, str]) -> str | None:
    normalized = value.rstrip(".。!！")
    for label, canonical in choices.items():
        if any(
            normalized == f"{label}{qualifier}{copula}"
            for qualifier in _UNAMBIGUOUS_CHOICE_QUALIFIERS
            for copula in _UNAMBIGUOUS_CHOICE_COPULAS
        ):
            return canonical
    return None


def parse_answer(field: str, text: str) -> object:
    value = text.strip()
    if field == "date_of_birth":
        korean_dates = re.findall(r"(\d{4})년\s*(\d{1,2})월\s*(\d{1,2})일", value)
        if len(korean_dates) == 1:
            year, month, day = (int(part) for part in korean_dates[0])
            return f"{year:04d}-{month:02d}-{day:02d}"
        if len(korean_dates) > 1:
            return value
    structured_fields = {
        "allergies",
        "intolerances",
        "religious_ethical_exclusions",
        "disliked_foods",
        "dietary_preferences",
        "conditions",
        "medications",
    }
    if field in structured_fields:
        if value.casefold() in {"없음", "none"} or value in _STRUCTURED_NONE_ANSWERS[field]:
            return {"status": "none", "items": []}
        return {
            "status": "provided",
            "items": [item.strip() for item in value.split(",")],
        }
    closed_choices = _CLOSED_CHOICES.get(field)
    if closed_choices is not None:
        exact = _parse_closed_choice(value, closed_choices)
        if exact is not None:
            return exact
    if field == "activity_category":
        exact = next(
            (
                category
                for label, category in _ACTIVITY_CATEGORIES.items()
                if value == f"{label} 활동량입니다."
            ),
            None,
        )
        if exact is not None:
            return exact
        legacy = parse_legacy_activity_answer(value)
        return legacy[0] if legacy is not None else value
    mappings = {
        "equation_sex_basis": {
            "네, 남성입니다.": "male",
            "네, 여성입니다.": "female",
        },
        "goal_type": {
            "현재 체중을 유지하고 싶습니다.": "maintain",
        },
    }
    if field in mappings:
        return mappings[field].get(value, value)
    if field in {"pregnancy_breastfeeding", "eating_disorder_risk"}:
        return _BOOLEAN_ANSWERS.get(value, value)
    if field in {"target_weight_kg", "target_date"} and (
        value.casefold() in {"없음", "none"}
        or "정하지 않겠습니다" in value
    ):
        return None
    unit = _MEASUREMENT_UNITS.get(field)
    if unit:
        measurement = _parse_measurement(value, unit)
        if measurement is not None:
            return measurement
    if field == "budget_band" and "보통" in value:
        return "보통"
    if field == "meal_count":
        counts = re.findall(
            rf"하루\s*(\d+|{'|'.join(_KOREAN_MEAL_COUNTS)})\s*끼",
            value,
        )
        if len(counts) == 1:
            count = counts[0]
            return int(count) if count.isdigit() else _KOREAN_MEAL_COUNTS[count]
        if len(counts) > 1:
            return value
        return _parse_meal_count(value)
    return value
