"""
generate_sample_data.py — GlucoClampTracer 합성 샘플 데이터 생성기
====================================================================

하이퍼인슐린혈성-정상혈당 클램프 실험의 현실적인 마우스 데이터를 합성한다.
외부 네트워크/API 없이 완전 오프라인으로 동작한다(numpy 난수만 사용).

생성 파일 (data/ 하위):
  - clamp_timeseries.csv  : 펌프 GIR / 혈당 / 체중 시계열
  - tracer_enrichment.csv : [3-3H]glucose / [6,6-2H2]glucose 트레이서 데이터
  - tissue_2dg.csv        : 조직 특이적 2-DG-6-P 측정값

3개 그룹 x 6마리 = 18마리 (Control, DIO, db/db).

재현: `python3 generate_sample_data.py` (data/ 폴더에 CSV 3종 생성)
"""

from __future__ import annotations

import os
import numpy as np
import pandas as pd

RNG = np.random.default_rng(20260518)  # 재현성을 위한 고정 시드
DATA_DIR = os.path.join(os.path.dirname(os.path.abspath(__file__)), "data")

# 그룹 정의: (그룹명, 마우스모델, n, 전형 GIR mg/kg/min, HGP억제%, 체중 g)
GROUPS = [
    ("Control", "C57BL/6", 6, 42.0, 88.0, 27.0),
    ("DIO",     "DIO",     6, 16.0, 50.0, 44.0),
    ("dbdb",    "db/db",   6, 6.0,  22.0, 48.0),
]

# 클램프 프로토콜: -120~0분 기저, 0~120분 클램프, 10분 간격 샘플
TIME_BASAL = np.arange(-30, 1, 10)        # 기저 트레이서 평형
TIME_CLAMP = np.arange(0, 121, 10)        # 클램프
ALL_TIME = np.concatenate([TIME_BASAL[:-1], TIME_CLAMP])

TISSUES = [
    "gastrocnemius", "soleus", "EDL", "tibialis",
    "heart", "BAT", "WAT", "liver",
]
# 조직별 상대 흡수 가중치(정상 마우스 기준 근사) — 적색근 > 백색근 > 지방
TISSUE_WEIGHT = {
    "gastrocnemius": 1.0, "soleus": 2.4, "EDL": 0.7, "tibialis": 0.9,
    "heart": 3.0, "BAT": 4.5, "WAT": 0.35, "liver": 0.5,
}


def _animal_ids():
    ids = []
    for gname, _model, n, *_ in GROUPS:
        for i in range(1, n + 1):
            ids.append((f"{gname}_{i:02d}", gname))
    return ids


def make_timeseries():
    """펌프 GIR / 혈당 / 체중 시계열 CSV 데이터프레임 생성."""
    rows = []
    for gname, model, n, gir_target, _hgp, bw_mean in GROUPS:
        for i in range(1, n + 1):
            aid = f"{gname}_{i:02d}"
            bw = float(np.round(RNG.normal(bw_mean, bw_mean * 0.06), 1))
            lean = float(np.round(bw * RNG.uniform(0.62, 0.72), 1))
            # 개체별 정상상태 GIR (mg/kg/min) -> mL/h 펌프 단위로 환산
            gir_ss_mgkgmin = max(RNG.normal(gir_target, gir_target * 0.18), 0.5)
            # mg/kg/min -> mg/min -> uL/min(0.2 mg/uL) -> mL/h
            mg_per_min = gir_ss_mgkgmin * (bw / 1000.0)
            uL_per_min = mg_per_min / 0.2
            gir_ss_mL_h = uL_per_min * 60.0 / 1000.0

            for t in ALL_TIME:
                if t <= 0:
                    gir = 0.0  # 기저에는 포도당 주입 없음
                    # 기저 혈당: 모델별 — db/db는 고혈당
                    base_g = {"C57BL/6": 150, "DIO": 175, "db/db": 320}[model]
                    glucose = RNG.normal(base_g, base_g * 0.05)
                else:
                    # 클램프 진입: GIR이 0->정상상태로 ramp-up (지수 접근)
                    ramp = 1.0 - np.exp(-t / 25.0)
                    gir = gir_ss_mL_h * ramp * RNG.normal(1.0, 0.04)
                    # 혈당을 목표 150으로 수렴 (초기 transient 후 안정)
                    target = 150.0
                    if t < 40:
                        glucose = RNG.normal(target + (40 - t) * 1.1, 12)
                    else:
                        glucose = RNG.normal(target, 6.5)
                rows.append({
                    "animal_id": aid,
                    "group": gname,
                    "model": model,
                    "time_min": int(t),
                    "gir_mL_per_h": round(max(gir, 0.0), 4),
                    "glucose_mg_dL": round(float(glucose), 1),
                    "body_weight_g": bw,
                    "lean_mass_g": lean,
                })
    return pd.DataFrame(rows)


def make_tracer():
    """[3-3H]glucose / [6,6-2H2]glucose 트레이서 enrichment CSV 생성.

    - tracer_3h_infusion_dpm_min : 트레이서 주입율(dpm/min)
    - plasma_3h_sa_dpm_per_mg    : 혈장 3H 비방사능 (dpm/mg glucose)
    - plasma_2h2_enrichment_pct  : 혈장 [6,6-2H2]glucose enrichment (MPE %)
    - basal vs clamp 각각 기록
    """
    rows = []
    # 트레이서 주입율은 동물 공통(프라이밍 후 일정)
    tir_3h = 1.10e6  # dpm/min
    for gname, model, n, gir_target, hgp_supp, bw_mean in GROUPS:
        for i in range(1, n + 1):
            aid = f"{gname}_{i:02d}"
            # 기저 HGP (mg/kg/min) — 모델별
            hgp_basal = {"C57BL/6": 22.0, "DIO": 28.0, "db/db": 38.0}[model]
            hgp_basal *= RNG.normal(1.0, 0.12)
            # 비방사능 SA = TIR / Ra  (기저: Ra = HGP_basal)
            # 단위 일치를 위해 SA 스케일은 임의 일관 단위로 둔다.
            sa_basal = tir_3h / max(hgp_basal, 1.0)
            # 클램프: Rd 증가 -> SA 하락. HGP 억제율 반영.
            hgp_clamp = hgp_basal * (1.0 - hgp_supp / 100.0 * RNG.normal(1.0, 0.1))
            gir_ss = max(RNG.normal(gir_target, gir_target * 0.18), 0.5)
            ra_clamp = hgp_clamp + gir_ss
            sa_clamp = tir_3h / max(ra_clamp, 1.0)
            # 안정동위원소 enrichment(%) — SA와 반비례 경향, 별도 트레이서
            enr_basal = 2.6 * (22.0 / max(hgp_basal, 1.0)) * RNG.normal(1.0, 0.08)
            enr_clamp = enr_basal * (hgp_basal / max(ra_clamp, 1.0)) * RNG.normal(1.0, 0.08)

            for state, sa, enr in (
                ("basal", sa_basal, enr_basal),
                ("clamp", sa_clamp, enr_clamp),
            ):
                rows.append({
                    "animal_id": aid,
                    "group": gname,
                    "model": model,
                    "state": state,
                    "tracer_3h_infusion_dpm_min": round(tir_3h, 1),
                    "plasma_3h_sa_dpm_per_mg": round(float(sa) * RNG.normal(1.0, 0.05), 2),
                    "plasma_2h2_enrichment_pct": round(float(enr) * RNG.normal(1.0, 0.05), 4),
                    "plasma_glucose_mg_dL": round(
                        150.0 if state == "clamp"
                        else {"C57BL/6": 150, "DIO": 175, "db/db": 320}[model]
                        * RNG.normal(1.0, 0.04), 1),
                    "hot_ginf_dpm_min": 0.0,  # 본 데이터셋은 cold GINF 사용
                })
    return pd.DataFrame(rows)


def make_tissue_2dg():
    """조직 특이적 2-DG-6-P 측정값 CSV 생성.

    - tissue_2dg6p_dpm_per_g : 조직 인산화 2-DG-6-P (dpm/g)
    - plasma_2dg_auc_dpm_min_per_mL : 혈장 2-DG 소실곡선 AUC
    - mean_plasma_glucose_mg_per_mL : 클램프 평균 혈장 포도당
    """
    rows = []
    for gname, model, n, gir_target, _hgp, _bw in GROUPS:
        # 모델별 전신 인슐린 감수성 스케일 (Control 1.0 기준)
        sens = {"C57BL/6": 1.0, "DIO": 0.45, "db/db": 0.18}[model]
        for i in range(1, n + 1):
            aid = f"{gname}_{i:02d}"
            plasma_auc = float(RNG.normal(3.4e6, 3.0e5))
            mean_glc = round(150.0 / 100.0 * RNG.normal(1.0, 0.03), 4)  # mg/mL
            for tissue in TISSUES:
                base = 9.0e4 * TISSUE_WEIGHT[tissue]
                val = base * sens * RNG.normal(1.0, 0.16)
                rows.append({
                    "animal_id": aid,
                    "group": gname,
                    "model": model,
                    "tissue": tissue,
                    "tissue_2dg6p_dpm_per_g": round(max(val, 0.0), 1),
                    "plasma_2dg_auc_dpm_min_per_mL": round(plasma_auc, 1),
                    "mean_plasma_glucose_mg_per_mL": mean_glc,
                })
    return pd.DataFrame(rows)


def main():
    os.makedirs(DATA_DIR, exist_ok=True)

    ts = make_timeseries()
    tr = make_tracer()
    tg = make_tissue_2dg()

    ts_path = os.path.join(DATA_DIR, "clamp_timeseries.csv")
    tr_path = os.path.join(DATA_DIR, "tracer_enrichment.csv")
    tg_path = os.path.join(DATA_DIR, "tissue_2dg.csv")

    ts.to_csv(ts_path, index=False)
    tr.to_csv(tr_path, index=False)
    tg.to_csv(tg_path, index=False)

    print(f"[OK] {ts_path}  ({len(ts)} rows, {ts['animal_id'].nunique()} animals)")
    print(f"[OK] {tr_path}  ({len(tr)} rows)")
    print(f"[OK] {tg_path}  ({len(tg)} rows, {len(TISSUES)} tissues)")
    print("합성 데이터 생성 완료.")


if __name__ == "__main__":
    main()
