"""MELD / MELD-Na / MELD 3.0 / Child-Pugh / CLIF-SOFA scoring.

References (built-in, offline):
- MELD (Kamath 2001), MELD-Na (Kim 2008), MELD 3.0 (Kim 2021, OPTN 2023)
- Child-Pugh (Pugh 1973)
- CLIF-SOFA / EASL-CLIF (Moreau 2013; Jalan 2014)

For research / quality-improvement use only. Not for clinical decision making.
"""
from __future__ import annotations

import math
from typing import Dict, Optional


# ---------------------------------------------------------------------------
# MELD family
# ---------------------------------------------------------------------------
def _clamp(x: float, lo: float, hi: float) -> float:
    return max(lo, min(hi, x))


def meld(bilirubin: float, inr: float, creatinine: float,
         dialysis: bool = False) -> float:
    """Classic MELD (Kamath 2001). Range 6-40."""
    bili = max(bilirubin, 1.0)
    inr_v = max(inr, 1.0)
    creat = max(creatinine, 1.0)
    if dialysis:
        creat = 4.0
    creat = min(creat, 4.0)
    score = (0.957 * math.log(creat)
             + 0.378 * math.log(bili)
             + 1.120 * math.log(inr_v)
             + 0.643) * 10
    return round(_clamp(score, 6, 40), 1)


def meld_na(bilirubin: float, inr: float, creatinine: float,
            sodium: float, dialysis: bool = False) -> float:
    """MELD-Na (Kim 2008). Sodium clamped to 125-137."""
    base = meld(bilirubin, inr, creatinine, dialysis)
    na = _clamp(sodium, 125, 137)
    if base > 11:
        score = base + 1.32 * (137 - na) - (0.033 * base * (137 - na))
    else:
        score = base
    return round(_clamp(score, 6, 40), 1)


def meld_3(bilirubin: float, inr: float, creatinine: float,
           sodium: float, albumin: float, female: bool,
           dialysis: bool = False) -> float:
    """MELD 3.0 (Kim 2021; OPTN adopted 2023-07).

    Score = 1.33*(female) + 4.56*ln(bili) + 0.82*(137-Na) - 0.24*(137-Na)*ln(bili)
            + 9.09*ln(INR) + 11.14*ln(creat) + 1.85*(3.5-alb) - 1.83*(3.5-alb)*ln(creat) + 6
    """
    bili = max(bilirubin, 1.0)
    inr_v = max(inr, 1.0)
    creat = max(creatinine, 1.0)
    if dialysis:
        creat = 3.0
    creat = min(creat, 3.0)
    na = _clamp(sodium, 125, 137)
    alb = _clamp(albumin, 1.5, 3.5)
    sex = 1.33 if female else 0.0
    score = (sex
             + 4.56 * math.log(bili)
             + 0.82 * (137 - na)
             - 0.24 * (137 - na) * math.log(bili)
             + 9.09 * math.log(inr_v)
             + 11.14 * math.log(creat)
             + 1.85 * (3.5 - alb)
             - 1.83 * (3.5 - alb) * math.log(creat)
             + 6.0)
    return round(_clamp(score, 6, 40), 1)


# ---------------------------------------------------------------------------
# Child-Pugh
# ---------------------------------------------------------------------------
def child_pugh(bilirubin: float, albumin: float, inr: float,
               ascites: str, he_grade: int) -> Dict[str, object]:
    """Child-Pugh score and class. ascites in {none, mild, moderate-severe}."""
    pts = 0
    pts += 1 if bilirubin < 2 else (2 if bilirubin <= 3 else 3)
    pts += 1 if albumin > 3.5 else (2 if albumin >= 2.8 else 3)
    pts += 1 if inr < 1.7 else (2 if inr <= 2.3 else 3)
    asc_map = {"none": 1, "mild": 2, "moderate-severe": 3}
    pts += asc_map.get(ascites, 1)
    if he_grade <= 0:
        pts += 1
    elif he_grade <= 2:
        pts += 2
    else:
        pts += 3
    if pts <= 6:
        cls = "A"
    elif pts <= 9:
        cls = "B"
    else:
        cls = "C"
    return {"score": pts, "class": cls}


# ---------------------------------------------------------------------------
# CLIF-SOFA (simplified, 6 organ systems × 0-3)
# ---------------------------------------------------------------------------
def clif_sofa(bilirubin: float, creatinine: float, inr: float,
              he_grade: int, map_mmhg: float,
              spo2_fio2: Optional[float] = None) -> Dict[str, int]:
    """Return CLIF-SOFA subscores (0-3) and total.

    Organ-failure thresholds (subscore >= 3) follow EASL-CLIF (Moreau 2013):
      liver:  bili >= 12 mg/dL
      kidney: creat >= 3.5 mg/dL (or RRT)
      coag:   INR >= 2.5
      brain:  West Haven grade III-IV
      circ:   MAP < 70 (vasopressor proxy at MAP < 60)
      resp:   SpO2/FiO2 <= 214
    """
    sub: Dict[str, int] = {}
    # Liver (bilirubin mg/dL)
    sub["liver"] = (0 if bilirubin < 6 else
                    1 if bilirubin < 8 else
                    2 if bilirubin < 12 else 3)
    # Kidney
    sub["kidney"] = (0 if creatinine < 2 else
                     1 if creatinine < 3.5 else 3)
    # Coagulation (INR)
    sub["coag"] = (0 if inr < 2 else
                   1 if inr < 2.5 else 3)
    # Brain (West Haven grade 0-IV)
    sub["brain"] = (0 if he_grade == 0 else
                    1 if he_grade == 1 else
                    2 if he_grade == 2 else 3)
    # Circulation (MAP / vasopressor proxy)
    sub["circ"] = (0 if map_mmhg >= 70 else
                   1 if map_mmhg >= 60 else 3)
    # Respiration (SpO2/FiO2 ratio proxy)
    if spo2_fio2 is None:
        sub["resp"] = 0
    else:
        sub["resp"] = (0 if spo2_fio2 > 357 else
                       1 if spo2_fio2 > 214 else 3)
    sub["total"] = sum(v for k, v in sub.items() if k != "total")
    return sub
