"""Semantic calorie and macronutrient claim integrity."""

from __future__ import annotations

import re
from typing import Mapping


_CALORIE_CLAIM_RE = re.compile(
    r"(?P<value>\d+(?:[.,]\d+)?)\s*(?:kcal|칼로리)",
    re.IGNORECASE,
)
_MACRO_CLAIM_RE = re.compile(
    r"(?:(?P<label>단백질|탄수화물|지방).{0,12}?"
    r"(?P<value>\d+(?:[.,]\d+)?)\s*(?:g|그램)"
    r"|(?P<reverse_value>\d+(?:[.,]\d+)?)\s*(?:g|그램)"
    r".{0,8}?(?P<reverse_label>단백질|탄수화물|지방))",
    re.IGNORECASE,
)


def recommendation_claims_match(
    candidate: str,
    locked: Mapping[str, int],
) -> bool:
    """Return whether labeled nutrition claims match their locked fields."""
    for match in _CALORIE_CLAIM_RE.finditer(candidate):
        if _claim_number(match.group("value")) != locked["calories"]:
            return False
    macro_keys = {
        "단백질": "protein_g",
        "탄수화물": "carbs_g",
        "지방": "fat_g",
    }
    for match in _MACRO_CLAIM_RE.finditer(candidate):
        label = match.group("label") or match.group("reverse_label")
        value = match.group("value") or match.group("reverse_value")
        if (
            label is None
            or value is None
            or _claim_number(value) != locked[macro_keys[label]]
        ):
            return False
    return True


def _claim_number(value: str) -> int | float:
    number = float(value.replace(",", ""))
    return int(number) if number.is_integer() else number
