"""predictive.py — REE 예측식 및 대사적응 지표.

지원 식:
- Mifflin-St Jeor (1990)
- Harris-Benedict (1919, 원식)
- Henry / Schofield (Henry 2005, Oxford 방정식; 연령·성별 구간 계수)
- Cunningham (1980, 제지방량 기반): REE = 500 + 22*FFM(kg)

측정 REE / 예측 REE 비 < ~0.90 이면 대사적응(metabolic adaptation) 의심
(흔히 사용되는 임의 임계; 연구 맥락에 따라 다름).

본 도구는 연구용·참고용이며 임상 의사결정에 직접 사용 금지.
"""

from __future__ import annotations


def mifflin_st_jeor(weight_kg, height_cm, age_y, sex):
    """Mifflin-St Jeor BMR (kcal/day). sex: 'M'/'F'."""
    s = 5 if str(sex).upper().startswith("M") else -161
    return 10 * weight_kg + 6.25 * height_cm - 5 * age_y + s


def harris_benedict(weight_kg, height_cm, age_y, sex):
    """Harris-Benedict 원식(1919) BMR (kcal/day)."""
    if str(sex).upper().startswith("M"):
        return 66.473 + 13.7516 * weight_kg + 5.0033 * height_cm - 6.7550 * age_y
    return 655.0955 + 9.5634 * weight_kg + 1.8496 * height_cm - 4.6756 * age_y


# Henry (2005) Oxford 방정식 — 체중·신장(m) 기반. 계수: (a_weight, b_height_m, c_const)
# 단순화를 위해 흔히 인용되는 weight+height 형태 사용.
_HENRY = {
    "M": [
        ((0, 3), (28.2, 859, -371)),
        ((3, 10), (15.1, 313, 306)),
        ((10, 18), (15.6, 266, 299)),
        ((18, 30), (14.4, 313, 113)),
        ((30, 60), (11.4, 541, -137)),
        ((60, 200), (11.4, 541, -256)),
    ],
    "F": [
        ((0, 3), (30.4, 703, -287)),
        ((3, 10), (15.9, 210, 349)),
        ((10, 18), (9.40, 249, 462)),
        ((18, 30), (10.4, 615, -282)),
        ((30, 60), (8.18, 502, -11.6)),
        ((60, 200), (8.52, 421, 10.7)),
    ],
}


def henry_schofield(weight_kg, height_cm, age_y, sex):
    """Henry(2005) Oxford BMR (kcal/day). height_cm -> m 로 사용."""
    key = "M" if str(sex).upper().startswith("M") else "F"
    height_m = height_cm / 100.0
    for (lo, hi), (a, b, c) in _HENRY[key]:
        if lo <= age_y < hi:
            return a * weight_kg + b * height_m + c
    a, b, c = _HENRY[key][-1][1]
    return a * weight_kg + b * height_m + c


def cunningham(ffm_kg):
    """Cunningham(1980) 제지방량 기반 RMR (kcal/day)."""
    if ffm_kg is None:
        return None
    return 500.0 + 22.0 * ffm_kg


def all_predictions(weight_kg, height_cm, age_y, sex, ffm_kg=None):
    """모든 예측식 결과 dict (kcal/day)."""
    out = {
        "Mifflin-St Jeor": mifflin_st_jeor(weight_kg, height_cm, age_y, sex),
        "Harris-Benedict": harris_benedict(weight_kg, height_cm, age_y, sex),
        "Henry/Schofield": henry_schofield(weight_kg, height_cm, age_y, sex),
    }
    if ffm_kg is not None:
        out["Cunningham(FFM)"] = cunningham(ffm_kg)
    return out


def metabolic_adaptation(measured_ree, predictions, adaptation_threshold=0.90):
    """측정/예측 비 및 대사적응 플래그.

    반환 dict: {식이름: {'predicted':..,'ratio':..,'adapted':bool}}
    """
    out = {}
    for name, pred in predictions.items():
        if pred is None or pred == 0:
            out[name] = {"predicted": pred, "ratio": None, "adapted": None}
            continue
        ratio = measured_ree / pred
        out[name] = {
            "predicted": float(pred),
            "ratio": float(ratio),
            "adapted": bool(ratio < adaptation_threshold),
        }
    return out
