"""DIO model-specific reference range library for mouse body composition.

Reference values are mid-range typical values gathered from published
literature on common rodent obesity / metabolic disease models. Values
are NOT manufacturer-validated and are provided strictly for offline
synthetic analysis and educational benchmarking inside this MVP.

Source notes (offline summary, no external calls):
    - DIO C57BL/6J HFD 60%kcal: Jackson Labs DIO Series 380050 phenotype
      profile (PIXImus DXA, EchoMRI), week 0-24.
    - ob/ob (B6.Cg-Lep^ob): hyperphagic, severe obesity from week 4.
    - db/db (BKS.Cg-Dock7^m +/+ Lepr^db): obese + diabetic.
    - NZO/HlLtJ: polygenic obesity, male-skewed.
    - KK-Ay: yellow obese mouse.
    - STAM (streptozotocin + HFD): NASH model, lean body composition.
    - GAN-DIO-NASH (Gubra Amylin NASH diet): obese NASH.
    - CDAA-HFD: choline-deficient L-amino acid + HFD NASH model.

All numeric values are *approximate central tendencies* for adult male
mice unless noted. fat_pct = fat_g / body_weight_g * 100.
"""

from __future__ import annotations

from typing import Dict, List

# Time points in weeks of intervention (post-diet-start or post-induction).
DEFAULT_TIME_POINTS_WK: List[int] = [0, 4, 8, 12, 16, 20]

# Reference dict: model -> time_point_wk -> band of typical values.
# Each band: dict with 'body_weight_g', 'fat_pct', 'lean_pct', 'BMD',
# 'BMC', 'visceral_fat_proxy_g', 'appendicular_lean_g'.
# Values are (low, mid, high) tuples representing approx 25-50-75 percentile.

DIO_REFERENCE: Dict[str, Dict[int, Dict[str, tuple]]] = {
    "C57BL_6J_chow": {
        0:  {"body_weight_g": (20.0, 22.5, 25.0), "fat_pct": (10, 13, 16), "lean_pct": (78, 80, 82), "BMD": (0.048, 0.052, 0.056), "BMC": (0.40, 0.45, 0.50), "visceral_fat_proxy_g": (0.4, 0.6, 0.9), "appendicular_lean_g": (4.5, 5.0, 5.5)},
        4:  {"body_weight_g": (22.0, 24.5, 27.0), "fat_pct": (11, 14, 17), "lean_pct": (77, 79, 81), "BMD": (0.050, 0.054, 0.058), "BMC": (0.42, 0.47, 0.52), "visceral_fat_proxy_g": (0.5, 0.7, 1.0), "appendicular_lean_g": (4.8, 5.3, 5.8)},
        8:  {"body_weight_g": (24.0, 26.5, 29.0), "fat_pct": (12, 15, 18), "lean_pct": (76, 78, 80), "BMD": (0.052, 0.056, 0.060), "BMC": (0.44, 0.49, 0.54), "visceral_fat_proxy_g": (0.6, 0.8, 1.2), "appendicular_lean_g": (5.0, 5.5, 6.0)},
        12: {"body_weight_g": (25.0, 27.5, 30.0), "fat_pct": (13, 16, 19), "lean_pct": (75, 77, 79), "BMD": (0.053, 0.057, 0.061), "BMC": (0.45, 0.50, 0.55), "visceral_fat_proxy_g": (0.7, 0.9, 1.3), "appendicular_lean_g": (5.1, 5.6, 6.1)},
        16: {"body_weight_g": (26.0, 28.5, 31.0), "fat_pct": (13, 16, 19), "lean_pct": (75, 77, 79), "BMD": (0.054, 0.058, 0.062), "BMC": (0.46, 0.51, 0.56), "visceral_fat_proxy_g": (0.7, 1.0, 1.4), "appendicular_lean_g": (5.2, 5.7, 6.2)},
        20: {"body_weight_g": (27.0, 29.5, 32.0), "fat_pct": (14, 17, 20), "lean_pct": (74, 76, 78), "BMD": (0.054, 0.058, 0.062), "BMC": (0.46, 0.51, 0.56), "visceral_fat_proxy_g": (0.8, 1.1, 1.5), "appendicular_lean_g": (5.3, 5.8, 6.3)},
    },
    "C57BL_6J_HFD60": {
        0:  {"body_weight_g": (20.0, 22.5, 25.0), "fat_pct": (10, 13, 16), "lean_pct": (78, 80, 82), "BMD": (0.048, 0.052, 0.056), "BMC": (0.40, 0.45, 0.50), "visceral_fat_proxy_g": (0.4, 0.6, 0.9), "appendicular_lean_g": (4.5, 5.0, 5.5)},
        4:  {"body_weight_g": (25.0, 28.0, 31.0), "fat_pct": (18, 22, 26), "lean_pct": (70, 73, 76), "BMD": (0.049, 0.053, 0.057), "BMC": (0.41, 0.46, 0.51), "visceral_fat_proxy_g": (1.5, 2.2, 3.0), "appendicular_lean_g": (4.9, 5.4, 5.9)},
        8:  {"body_weight_g": (30.0, 34.0, 38.0), "fat_pct": (28, 33, 38), "lean_pct": (60, 64, 68), "BMD": (0.050, 0.054, 0.058), "BMC": (0.42, 0.47, 0.52), "visceral_fat_proxy_g": (3.0, 4.5, 6.0), "appendicular_lean_g": (5.2, 5.7, 6.2)},
        12: {"body_weight_g": (35.0, 40.0, 45.0), "fat_pct": (35, 41, 46), "lean_pct": (52, 57, 62), "BMD": (0.051, 0.055, 0.059), "BMC": (0.43, 0.48, 0.53), "visceral_fat_proxy_g": (4.5, 6.5, 8.5), "appendicular_lean_g": (5.4, 5.9, 6.4)},
        16: {"body_weight_g": (40.0, 45.0, 50.0), "fat_pct": (40, 46, 51), "lean_pct": (47, 52, 57), "BMD": (0.051, 0.055, 0.059), "BMC": (0.43, 0.48, 0.53), "visceral_fat_proxy_g": (6.0, 8.5, 11.0), "appendicular_lean_g": (5.5, 6.0, 6.5)},
        20: {"body_weight_g": (43.0, 48.0, 53.0), "fat_pct": (43, 49, 54), "lean_pct": (44, 49, 54), "BMD": (0.051, 0.055, 0.059), "BMC": (0.43, 0.48, 0.53), "visceral_fat_proxy_g": (7.0, 10.0, 13.0), "appendicular_lean_g": (5.6, 6.1, 6.6)},
    },
    "ob_ob": {
        0:  {"body_weight_g": (22.0, 25.0, 28.0), "fat_pct": (20, 25, 30), "lean_pct": (65, 70, 75), "BMD": (0.045, 0.049, 0.053), "BMC": (0.36, 0.41, 0.46), "visceral_fat_proxy_g": (1.5, 2.5, 3.5), "appendicular_lean_g": (4.0, 4.5, 5.0)},
        4:  {"body_weight_g": (32.0, 37.0, 42.0), "fat_pct": (45, 52, 58), "lean_pct": (40, 45, 50), "BMD": (0.045, 0.049, 0.053), "BMC": (0.37, 0.42, 0.47), "visceral_fat_proxy_g": (5.0, 8.0, 11.0), "appendicular_lean_g": (4.2, 4.7, 5.2)},
        8:  {"body_weight_g": (42.0, 48.0, 54.0), "fat_pct": (55, 62, 68), "lean_pct": (30, 35, 40), "BMD": (0.045, 0.049, 0.053), "BMC": (0.38, 0.43, 0.48), "visceral_fat_proxy_g": (9.0, 13.0, 17.0), "appendicular_lean_g": (4.3, 4.8, 5.3)},
        12: {"body_weight_g": (50.0, 56.0, 62.0), "fat_pct": (60, 65, 70), "lean_pct": (28, 33, 38), "BMD": (0.044, 0.048, 0.052), "BMC": (0.38, 0.43, 0.48), "visceral_fat_proxy_g": (11.0, 16.0, 21.0), "appendicular_lean_g": (4.4, 4.9, 5.4)},
        16: {"body_weight_g": (55.0, 62.0, 68.0), "fat_pct": (62, 68, 72), "lean_pct": (26, 31, 36), "BMD": (0.044, 0.048, 0.052), "BMC": (0.38, 0.43, 0.48), "visceral_fat_proxy_g": (13.0, 18.0, 23.0), "appendicular_lean_g": (4.4, 4.9, 5.4)},
        20: {"body_weight_g": (58.0, 65.0, 72.0), "fat_pct": (63, 69, 73), "lean_pct": (25, 30, 35), "BMD": (0.044, 0.048, 0.052), "BMC": (0.38, 0.43, 0.48), "visceral_fat_proxy_g": (14.0, 19.0, 24.0), "appendicular_lean_g": (4.4, 4.9, 5.4)},
    },
    "db_db": {
        0:  {"body_weight_g": (22.0, 25.0, 28.0), "fat_pct": (20, 25, 30), "lean_pct": (65, 70, 75), "BMD": (0.044, 0.048, 0.052), "BMC": (0.36, 0.41, 0.46), "visceral_fat_proxy_g": (1.5, 2.5, 3.5), "appendicular_lean_g": (4.0, 4.5, 5.0)},
        4:  {"body_weight_g": (30.0, 35.0, 40.0), "fat_pct": (40, 47, 53), "lean_pct": (44, 49, 54), "BMD": (0.043, 0.047, 0.051), "BMC": (0.36, 0.41, 0.46), "visceral_fat_proxy_g": (4.0, 7.0, 10.0), "appendicular_lean_g": (4.1, 4.6, 5.1)},
        8:  {"body_weight_g": (40.0, 46.0, 52.0), "fat_pct": (50, 57, 63), "lean_pct": (34, 39, 44), "BMD": (0.042, 0.046, 0.050), "BMC": (0.36, 0.41, 0.46), "visceral_fat_proxy_g": (8.0, 12.0, 16.0), "appendicular_lean_g": (4.2, 4.7, 5.2)},
        12: {"body_weight_g": (45.0, 52.0, 58.0), "fat_pct": (55, 62, 68), "lean_pct": (30, 35, 40), "BMD": (0.041, 0.045, 0.049), "BMC": (0.35, 0.40, 0.45), "visceral_fat_proxy_g": (10.0, 14.0, 19.0), "appendicular_lean_g": (4.2, 4.7, 5.2)},
        16: {"body_weight_g": (47.0, 54.0, 60.0), "fat_pct": (57, 64, 70), "lean_pct": (28, 33, 38), "BMD": (0.040, 0.044, 0.048), "BMC": (0.35, 0.40, 0.45), "visceral_fat_proxy_g": (11.0, 15.0, 20.0), "appendicular_lean_g": (4.2, 4.7, 5.2)},
        20: {"body_weight_g": (48.0, 55.0, 61.0), "fat_pct": (58, 65, 70), "lean_pct": (27, 32, 37), "BMD": (0.040, 0.044, 0.048), "BMC": (0.35, 0.40, 0.45), "visceral_fat_proxy_g": (11.0, 16.0, 21.0), "appendicular_lean_g": (4.2, 4.7, 5.2)},
    },
    "NZO": {
        0:  {"body_weight_g": (28.0, 31.0, 34.0), "fat_pct": (22, 27, 32), "lean_pct": (62, 67, 72), "BMD": (0.050, 0.054, 0.058), "BMC": (0.42, 0.47, 0.52), "visceral_fat_proxy_g": (2.0, 3.0, 4.0), "appendicular_lean_g": (5.0, 5.5, 6.0)},
        4:  {"body_weight_g": (35.0, 40.0, 45.0), "fat_pct": (35, 41, 47), "lean_pct": (50, 55, 60), "BMD": (0.051, 0.055, 0.059), "BMC": (0.43, 0.48, 0.53), "visceral_fat_proxy_g": (5.0, 8.0, 11.0), "appendicular_lean_g": (5.3, 5.8, 6.3)},
        8:  {"body_weight_g": (42.0, 48.0, 54.0), "fat_pct": (45, 51, 57), "lean_pct": (40, 45, 50), "BMD": (0.052, 0.056, 0.060), "BMC": (0.44, 0.49, 0.54), "visceral_fat_proxy_g": (8.0, 12.0, 16.0), "appendicular_lean_g": (5.5, 6.0, 6.5)},
        12: {"body_weight_g": (50.0, 56.0, 62.0), "fat_pct": (50, 56, 62), "lean_pct": (35, 40, 45), "BMD": (0.053, 0.057, 0.061), "BMC": (0.45, 0.50, 0.55), "visceral_fat_proxy_g": (10.0, 14.0, 18.0), "appendicular_lean_g": (5.6, 6.1, 6.6)},
        16: {"body_weight_g": (54.0, 60.0, 66.0), "fat_pct": (53, 59, 65), "lean_pct": (32, 37, 42), "BMD": (0.053, 0.057, 0.061), "BMC": (0.45, 0.50, 0.55), "visceral_fat_proxy_g": (11.0, 15.0, 20.0), "appendicular_lean_g": (5.6, 6.1, 6.6)},
        20: {"body_weight_g": (56.0, 62.0, 68.0), "fat_pct": (55, 60, 66), "lean_pct": (30, 35, 40), "BMD": (0.053, 0.057, 0.061), "BMC": (0.45, 0.50, 0.55), "visceral_fat_proxy_g": (12.0, 16.0, 21.0), "appendicular_lean_g": (5.7, 6.2, 6.7)},
    },
    "KK_Ay": {
        0:  {"body_weight_g": (24.0, 27.0, 30.0), "fat_pct": (18, 23, 28), "lean_pct": (66, 71, 76), "BMD": (0.047, 0.051, 0.055), "BMC": (0.39, 0.44, 0.49), "visceral_fat_proxy_g": (1.5, 2.5, 3.5), "appendicular_lean_g": (4.5, 5.0, 5.5)},
        4:  {"body_weight_g": (30.0, 34.0, 38.0), "fat_pct": (32, 38, 44), "lean_pct": (52, 57, 62), "BMD": (0.048, 0.052, 0.056), "BMC": (0.40, 0.45, 0.50), "visceral_fat_proxy_g": (4.0, 6.5, 9.0), "appendicular_lean_g": (4.7, 5.2, 5.7)},
        8:  {"body_weight_g": (35.0, 40.0, 45.0), "fat_pct": (42, 48, 54), "lean_pct": (42, 47, 52), "BMD": (0.048, 0.052, 0.056), "BMC": (0.40, 0.45, 0.50), "visceral_fat_proxy_g": (6.0, 9.0, 12.0), "appendicular_lean_g": (4.9, 5.4, 5.9)},
        12: {"body_weight_g": (40.0, 45.0, 50.0), "fat_pct": (48, 54, 60), "lean_pct": (36, 41, 46), "BMD": (0.048, 0.052, 0.056), "BMC": (0.40, 0.45, 0.50), "visceral_fat_proxy_g": (8.0, 11.0, 15.0), "appendicular_lean_g": (5.0, 5.5, 6.0)},
        16: {"body_weight_g": (42.0, 47.0, 52.0), "fat_pct": (50, 56, 62), "lean_pct": (34, 39, 44), "BMD": (0.048, 0.052, 0.056), "BMC": (0.40, 0.45, 0.50), "visceral_fat_proxy_g": (9.0, 12.0, 16.0), "appendicular_lean_g": (5.0, 5.5, 6.0)},
        20: {"body_weight_g": (43.0, 48.0, 53.0), "fat_pct": (51, 57, 63), "lean_pct": (33, 38, 43), "BMD": (0.048, 0.052, 0.056), "BMC": (0.40, 0.45, 0.50), "visceral_fat_proxy_g": (9.0, 12.5, 16.5), "appendicular_lean_g": (5.0, 5.5, 6.0)},
    },
    "STAM": {
        # STAM = STZ + HFD; lean despite HFD due to insulin loss
        0:  {"body_weight_g": (12.0, 14.0, 16.0), "fat_pct": (8, 11, 14), "lean_pct": (78, 81, 84), "BMD": (0.040, 0.044, 0.048), "BMC": (0.30, 0.35, 0.40), "visceral_fat_proxy_g": (0.2, 0.4, 0.6), "appendicular_lean_g": (3.0, 3.5, 4.0)},
        4:  {"body_weight_g": (18.0, 20.0, 22.0), "fat_pct": (12, 15, 18), "lean_pct": (74, 77, 80), "BMD": (0.045, 0.049, 0.053), "BMC": (0.34, 0.39, 0.44), "visceral_fat_proxy_g": (0.5, 0.8, 1.2), "appendicular_lean_g": (3.6, 4.1, 4.6)},
        8:  {"body_weight_g": (22.0, 25.0, 28.0), "fat_pct": (16, 20, 24), "lean_pct": (68, 72, 76), "BMD": (0.046, 0.050, 0.054), "BMC": (0.37, 0.42, 0.47), "visceral_fat_proxy_g": (1.0, 1.6, 2.2), "appendicular_lean_g": (4.0, 4.5, 5.0)},
        12: {"body_weight_g": (23.0, 26.0, 29.0), "fat_pct": (18, 22, 26), "lean_pct": (66, 70, 74), "BMD": (0.045, 0.049, 0.053), "BMC": (0.37, 0.42, 0.47), "visceral_fat_proxy_g": (1.2, 1.8, 2.5), "appendicular_lean_g": (4.0, 4.5, 5.0)},
        16: {"body_weight_g": (22.0, 25.0, 28.0), "fat_pct": (18, 22, 26), "lean_pct": (66, 70, 74), "BMD": (0.044, 0.048, 0.052), "BMC": (0.36, 0.41, 0.46), "visceral_fat_proxy_g": (1.2, 1.8, 2.5), "appendicular_lean_g": (3.9, 4.4, 4.9)},
        20: {"body_weight_g": (20.0, 23.0, 26.0), "fat_pct": (17, 21, 25), "lean_pct": (66, 70, 74), "BMD": (0.043, 0.047, 0.051), "BMC": (0.36, 0.41, 0.46), "visceral_fat_proxy_g": (1.0, 1.6, 2.2), "appendicular_lean_g": (3.7, 4.2, 4.7)},
    },
    "GAN_DIO_NASH": {
        0:  {"body_weight_g": (22.0, 25.0, 28.0), "fat_pct": (12, 15, 18), "lean_pct": (74, 77, 80), "BMD": (0.048, 0.052, 0.056), "BMC": (0.40, 0.45, 0.50), "visceral_fat_proxy_g": (0.5, 0.8, 1.2), "appendicular_lean_g": (4.5, 5.0, 5.5)},
        4:  {"body_weight_g": (28.0, 32.0, 36.0), "fat_pct": (22, 28, 34), "lean_pct": (62, 67, 72), "BMD": (0.049, 0.053, 0.057), "BMC": (0.41, 0.46, 0.51), "visceral_fat_proxy_g": (2.5, 4.0, 5.5), "appendicular_lean_g": (4.8, 5.3, 5.8)},
        8:  {"body_weight_g": (34.0, 39.0, 44.0), "fat_pct": (32, 38, 44), "lean_pct": (52, 57, 62), "BMD": (0.050, 0.054, 0.058), "BMC": (0.42, 0.47, 0.52), "visceral_fat_proxy_g": (4.5, 7.0, 9.5), "appendicular_lean_g": (5.0, 5.5, 6.0)},
        12: {"body_weight_g": (38.0, 44.0, 50.0), "fat_pct": (40, 46, 52), "lean_pct": (45, 50, 55), "BMD": (0.050, 0.054, 0.058), "BMC": (0.42, 0.47, 0.52), "visceral_fat_proxy_g": (6.5, 9.5, 12.5), "appendicular_lean_g": (5.1, 5.6, 6.1)},
        16: {"body_weight_g": (42.0, 48.0, 54.0), "fat_pct": (45, 51, 57), "lean_pct": (40, 45, 50), "BMD": (0.050, 0.054, 0.058), "BMC": (0.42, 0.47, 0.52), "visceral_fat_proxy_g": (8.0, 11.0, 14.0), "appendicular_lean_g": (5.2, 5.7, 6.2)},
        20: {"body_weight_g": (45.0, 51.0, 57.0), "fat_pct": (48, 54, 60), "lean_pct": (37, 42, 47), "BMD": (0.050, 0.054, 0.058), "BMC": (0.42, 0.47, 0.52), "visceral_fat_proxy_g": (9.0, 12.0, 15.0), "appendicular_lean_g": (5.2, 5.7, 6.2)},
    },
    "CDAA_HFD": {
        0:  {"body_weight_g": (22.0, 25.0, 28.0), "fat_pct": (12, 15, 18), "lean_pct": (74, 77, 80), "BMD": (0.048, 0.052, 0.056), "BMC": (0.40, 0.45, 0.50), "visceral_fat_proxy_g": (0.5, 0.8, 1.2), "appendicular_lean_g": (4.5, 5.0, 5.5)},
        4:  {"body_weight_g": (24.0, 27.0, 30.0), "fat_pct": (15, 19, 23), "lean_pct": (70, 74, 78), "BMD": (0.048, 0.052, 0.056), "BMC": (0.40, 0.45, 0.50), "visceral_fat_proxy_g": (1.0, 1.6, 2.2), "appendicular_lean_g": (4.6, 5.1, 5.6)},
        8:  {"body_weight_g": (26.0, 29.0, 32.0), "fat_pct": (18, 22, 26), "lean_pct": (68, 72, 76), "BMD": (0.048, 0.052, 0.056), "BMC": (0.40, 0.45, 0.50), "visceral_fat_proxy_g": (1.5, 2.3, 3.1), "appendicular_lean_g": (4.7, 5.2, 5.7)},
        12: {"body_weight_g": (28.0, 31.0, 34.0), "fat_pct": (20, 25, 30), "lean_pct": (64, 68, 72), "BMD": (0.047, 0.051, 0.055), "BMC": (0.40, 0.45, 0.50), "visceral_fat_proxy_g": (2.0, 3.0, 4.0), "appendicular_lean_g": (4.7, 5.2, 5.7)},
        16: {"body_weight_g": (29.0, 32.0, 35.0), "fat_pct": (22, 27, 32), "lean_pct": (62, 66, 70), "BMD": (0.046, 0.050, 0.054), "BMC": (0.40, 0.45, 0.50), "visceral_fat_proxy_g": (2.5, 3.5, 4.5), "appendicular_lean_g": (4.7, 5.2, 5.7)},
        20: {"body_weight_g": (29.0, 32.0, 35.0), "fat_pct": (23, 28, 33), "lean_pct": (61, 65, 69), "BMD": (0.045, 0.049, 0.053), "BMC": (0.40, 0.45, 0.50), "visceral_fat_proxy_g": (2.8, 3.8, 4.8), "appendicular_lean_g": (4.7, 5.2, 5.7)},
    },
}

# Convenience: list available models for UI.
AVAILABLE_MODELS = sorted(DIO_REFERENCE.keys())


def get_reference(model: str, time_point_wk: int) -> Dict[str, tuple]:
    """Return the reference band dict for (model, time_point).

    Falls back to the closest known time point if exact one is missing.
    Raises KeyError if model is unknown.
    """
    if model not in DIO_REFERENCE:
        raise KeyError(f"Unknown DIO model: {model}. Known: {AVAILABLE_MODELS}")
    bands = DIO_REFERENCE[model]
    if time_point_wk in bands:
        return bands[time_point_wk]
    # find closest
    closest = min(bands.keys(), key=lambda x: abs(x - time_point_wk))
    return bands[closest]


def classify_band(value: float, band: tuple) -> str:
    """Classify a measured value against a (low, mid, high) reference band.

    Returns one of: 'below', 'lower-normal', 'normal', 'upper-normal',
    'above'.
    """
    low, mid, high = band
    width = high - low
    if width <= 0:
        width = max(abs(mid) * 0.1, 1e-6)
    if value < low - 0.5 * width:
        return "below"
    if value < low:
        return "lower-normal"
    if value <= high:
        return "normal"
    if value <= high + 0.5 * width:
        return "upper-normal"
    return "above"


def reference_table() -> list:
    """Return a flat list-of-dicts representation for UI / export."""
    rows = []
    for model, by_time in DIO_REFERENCE.items():
        for t, band in by_time.items():
            row = {"model": model, "time_point_wk": t}
            for k, v in band.items():
                row[f"{k}_low"] = v[0]
                row[f"{k}_mid"] = v[1]
                row[f"{k}_high"] = v[2]
            rows.append(row)
    return rows


if __name__ == "__main__":
    print(f"Models: {AVAILABLE_MODELS}")
    print(f"Time points: {DEFAULT_TIME_POINTS_WK}")
    sample = get_reference("C57BL_6J_HFD60", 12)
    print(f"C57BL/6J HFD60 wk12: {sample}")
