"""
scales.py — MASHePRO-Kor 5종 척도 정의 + scoring + 검증 상태 메타데이터.

각 척도별 메타데이터:
- name_kr / name_en
- items: [{id, text_kr, options(가중치 dict 또는 numeric range)}]
- scoring: 함수 이름
- validation_status: 한국어판 검증 상태 (투명성 라벨)
- references: 인용

연구·교육용 prototype이며, 실제 임상 사용 시 IRB 검토 필수.
"""
from __future__ import annotations

# -------------------------------------------------------------------
# 1. CLDQ-NASH-Kor (Chronic Liver Disease Questionnaire - NASH, Korean)
#    원판 36문항 → 본 prototype은 단축형 자가검증 데모(8문항)만 포함.
#    검증 상태: 영문판 NASH 검증(Younossi 2018), 한국어판 → 일부 hepatology
#    문헌에서 forward-back translation 사용 보고. 정식 한글 psychometric
#    공식 보고는 제한적. 본 데모에서는 "단축 demo, 정식 검증 미완" 표기.
# -------------------------------------------------------------------
CLDQ_NASH_KOR_DEMO = {
    "id": "CLDQ_NASH_KOR_DEMO",
    "name_kr": "CLDQ-NASH 한국어 단축형 (데모)",
    "name_en": "CLDQ-NASH Korean Short Form (Demo)",
    "domains": ["복부증상", "활력도", "감정기능", "걱정"],
    "scale": "1=항상 있음 ~ 7=전혀 없음 (점수 높을수록 삶의 질 양호)",
    "items": [
        {"id": "cldq1", "domain": "복부증상", "text_kr": "지난 2주간 복부 불편감을 얼마나 자주 느끼셨습니까?"},
        {"id": "cldq2", "domain": "복부증상", "text_kr": "지난 2주간 복부 팽만감(배가 부풀어 오르는 느낌)이 얼마나 자주 있었습니까?"},
        {"id": "cldq3", "domain": "활력도",   "text_kr": "지난 2주간 신체 활동(걷기, 계단 오르기)에 어려움이 얼마나 있었습니까?"},
        {"id": "cldq4", "domain": "활력도",   "text_kr": "지난 2주간 일상 활동에서 활력이 부족하다고 느낀 빈도는?"},
        {"id": "cldq5", "domain": "감정기능", "text_kr": "지난 2주간 우울하거나 의기소침함을 얼마나 자주 느꼈습니까?"},
        {"id": "cldq6", "domain": "감정기능", "text_kr": "지난 2주간 짜증이 자주 났습니까?"},
        {"id": "cldq7", "domain": "걱정",     "text_kr": "지난 2주간 간 질환이 진행될까 걱정한 빈도는?"},
        {"id": "cldq8", "domain": "걱정",     "text_kr": "지난 2주간 가족에게 부담이 될까 걱정한 빈도는?"},
    ],
    "response_range": (1, 7),
    "scoring": "mean_per_domain_then_total_mean",
    "validation_status": {
        "label": "원판 영문 NASH 검증 완료 (Younossi 2018), 한국어판은 forward-back 번역만 보고. 정식 psychometric 검증 미완.",
        "level": "PARTIAL",
    },
    "references": [
        "Younossi ZM et al. CLDQ-NASH validation. Hepatology 2018.",
        "FDA Draft Guidance for NASH 2018",
    ],
}

# -------------------------------------------------------------------
# 2. FACIT-Fatigue-Kor (13문항)
# -------------------------------------------------------------------
FACIT_FATIGUE_KOR = {
    "id": "FACIT_FATIGUE_KOR",
    "name_kr": "FACIT-피로척도 한국어판 (13문항)",
    "name_en": "FACIT-Fatigue Korean (13 items)",
    "scale": "0=전혀 그렇지 않다 ~ 4=매우 그렇다 (역문항 처리 후 0–52, 점수 높을수록 양호)",
    "items": [
        {"id": f"facit{i+1}", "text_kr": text, "reverse": rev}
        for i, (text, rev) in enumerate([
            ("나는 기운이 없다.", True),
            ("나는 전신이 약하다.", True),
            ("나는 무기력하다.", True),
            ("나는 피곤하다.", True),
            ("나는 일을 시작하기가 어렵다. 피곤해서.", True),
            ("나는 일을 끝내기가 어렵다. 피곤해서.", True),
            ("나는 활력이 있다.", False),
            ("나는 평소 하던 일을 할 수 있다.", False),
            ("나는 낮에 자야 한다.", True),
            ("나는 너무 피곤해서 식사를 못 한다.", True),
            ("나는 평소 활동을 할 도움이 필요하다.", True),
            ("나는 피곤 때문에 평소 사회 활동에 좌절감을 느낀다.", True),
            ("나는 피곤 때문에 평소 하고 싶은 일을 제한해야 한다.", True),
        ])
    ],
    "response_range": (0, 4),
    "scoring": "facit_fatigue_total",
    "validation_status": {
        "label": "FACIT-Fatigue 한국어판 정식 검증 완료 (Cella 1997 원판; 한국어판 다수 종양·만성질환 연구에서 신뢰도 보고)",
        "level": "VALIDATED",
    },
    "references": [
        "Cella D, FACIT measurement system",
        "Korean translation: FACIT.org licensed",
    ],
}

# -------------------------------------------------------------------
# 3. PROMIS-Fatigue-Kor SF8a (8문항)
# -------------------------------------------------------------------
PROMIS_FATIGUE_KOR_SF8A = {
    "id": "PROMIS_FATIGUE_KOR_SF8A",
    "name_kr": "PROMIS-피로 한국어 단축형 8a",
    "name_en": "PROMIS-Fatigue Korean SF8a",
    "scale": "1=전혀 ~ 5=매우 (총점 8–40 → T-score 변환)",
    "items": [
        {"id": f"promis{i+1}", "text_kr": text}
        for i, text in enumerate([
            "지난 7일 동안 얼마나 자주 피곤함을 느꼈습니까?",
            "지난 7일 동안 신체적으로 얼마나 약하다고 느꼈습니까?",
            "지난 7일 동안 평소 활동을 마칠 만큼 충분한 에너지가 있었습니까? (역)",
            "지난 7일 동안 가족과 시간을 보내기에 너무 피곤했습니까?",
            "지난 7일 동안 정신적인 피로감을 얼마나 자주 느꼈습니까?",
            "지난 7일 동안 휴식 후에도 피로가 가시지 않았습니까?",
            "지난 7일 동안 피로가 일상생활을 방해했습니까?",
            "지난 7일 동안 평소 운동량을 줄여야 했습니까?",
        ])
    ],
    "response_range": (1, 5),
    "scoring": "promis_raw_to_tscore",
    "validation_status": {
        "label": "PROMIS Korean translation: PROMIS Health Organization 공식 번역; 일부 한국 연구에서 사용. SF8a 한국어 정식 calibration 진행 중.",
        "level": "PARTIAL",
    },
    "references": [
        "PROMIS Health Organization translation registry",
        "Cella D, PROMIS overview",
    ],
}

# -------------------------------------------------------------------
# 4. Hepatic Itch NRS (간소양감 NRS, 0–10)
# -------------------------------------------------------------------
HEPATIC_ITCH_NRS = {
    "id": "HEPATIC_ITCH_NRS",
    "name_kr": "간소양감 NRS (0–10)",
    "name_en": "Hepatic Itch Numeric Rating Scale",
    "scale": "0=가려움 없음 ~ 10=상상 가능한 가장 심한 가려움",
    "items": [
        {"id": "itch_now", "text_kr": "지난 24시간 평균 가려움 정도를 0–10으로 평가하세요."},
        {"id": "itch_worst", "text_kr": "지난 24시간 가장 심했던 가려움 정도를 0–10으로 평가하세요."},
    ],
    "response_range": (0, 10),
    "scoring": "itch_average",
    "validation_status": {
        "label": "NRS는 단순 척도로 별도 한국어 검증 불필요; PBC·간담즙성 가려움 연구에서 광범위 사용.",
        "level": "STANDARD",
    },
    "references": [
        "ICE-NASH 2023 PRO consensus",
        "Kremer AE et al. cholestatic itch NRS",
    ],
}

# -------------------------------------------------------------------
# 5. EQ-5D-5L-Kor (5문항 + VAS)
# -------------------------------------------------------------------
EQ5D5L_KOR = {
    "id": "EQ5D5L_KOR",
    "name_kr": "EQ-5D-5L 한국어판",
    "name_en": "EQ-5D-5L Korean",
    "scale": "각 차원 1=문제없음 ~ 5=극심한 문제, VAS 0–100",
    "items": [
        {"id": "eq_mobility",   "text_kr": "운동능력: 오늘 당신의 운동능력은 어떠합니까?"},
        {"id": "eq_selfcare",   "text_kr": "자기관리: 오늘 당신의 자기관리(씻기/옷입기) 능력은?"},
        {"id": "eq_usual",      "text_kr": "일상활동: 오늘 당신의 일상활동(일/공부/가사) 수행은?"},
        {"id": "eq_pain",       "text_kr": "통증/불편: 오늘 통증이나 불편감이 있으십니까?"},
        {"id": "eq_anxiety",    "text_kr": "불안/우울: 오늘 불안하거나 우울하십니까?"},
        {"id": "eq_vas",        "text_kr": "오늘의 건강 상태(VAS, 0=상상 가능한 최악, 100=상상 가능한 최상)",
         "type": "vas", "range": (0, 100)},
    ],
    "response_range": (1, 5),
    "scoring": "eq5d_korean_value_set",
    "validation_status": {
        "label": "EQ-5D-5L 한국어판 정식 검증 완료 (Kim SH et al. 한국 value set 발표)",
        "level": "VALIDATED",
    },
    "references": [
        "Kim SH et al. Korean EQ-5D-5L value set. Qual Life Res 2016.",
        "EuroQol Group official Korean translation",
    ],
}

ALL_SCALES = [
    CLDQ_NASH_KOR_DEMO,
    FACIT_FATIGUE_KOR,
    PROMIS_FATIGUE_KOR_SF8A,
    HEPATIC_ITCH_NRS,
    EQ5D5L_KOR,
]


# -------------------------------------------------------------------
# Scoring 함수들 (단순화)
# -------------------------------------------------------------------
def score_cldq(answers: dict) -> dict:
    """CLDQ demo: 도메인별 평균, 총점 평균. 1–7."""
    domains = {}
    for it in CLDQ_NASH_KOR_DEMO["items"]:
        v = answers.get(it["id"])
        if v is None:
            continue
        domains.setdefault(it["domain"], []).append(float(v))
    domain_means = {k: sum(v) / len(v) for k, v in domains.items() if v}
    total = sum(domain_means.values()) / len(domain_means) if domain_means else None
    return {"domain_means": domain_means, "total_mean": total}


def score_facit_fatigue(answers: dict) -> dict:
    """FACIT-Fatigue: 역문항 (4 - x) 처리 후 합. 0–52, 높을수록 양호."""
    total = 0
    n = 0
    for it in FACIT_FATIGUE_KOR["items"]:
        v = answers.get(it["id"])
        if v is None:
            continue
        v = float(v)
        if it["reverse"]:
            v = 4 - v
        total += v
        n += 1
    if n != len(FACIT_FATIGUE_KOR["items"]):
        # prorate 시연
        total = total * len(FACIT_FATIGUE_KOR["items"]) / max(n, 1)
    return {"total": total, "n_answered": n, "max": 52}


def score_promis_fatigue(answers: dict) -> dict:
    """PROMIS-Fatigue SF8a: raw 합산, 단순 선형 변환으로 T-score 시연.
    실제 PROMIS는 IRT scoring 필요; 여기서는 데모용 근사.
    """
    raw = 0
    n = 0
    for it in PROMIS_FATIGUE_KOR_SF8A["items"]:
        v = answers.get(it["id"])
        if v is None:
            continue
        raw += float(v)
        n += 1
    # 데모 근사: raw 8–40 → T 30–80 선형 매핑
    if n == 0:
        return {"raw": 0, "tscore": None, "approx": True}
    tscore = 30 + (raw - 8) * (80 - 30) / (40 - 8)
    return {"raw": raw, "tscore": round(tscore, 1), "approx": True,
            "note": "데모 근사. 정식 IRT scoring 필요."}


def score_itch(answers: dict) -> dict:
    vals = [float(answers[it["id"]]) for it in HEPATIC_ITCH_NRS["items"]
            if answers.get(it["id"]) is not None]
    if not vals:
        return {"average": None, "worst": None}
    return {
        "average_24h": float(answers.get("itch_now", vals[0])),
        "worst_24h":  float(answers.get("itch_worst", vals[-1])),
    }


# Korean EQ-5D-5L value set (Kim SH 2016) — 단순 데모용 가중치
# 실제 값과는 다른 근사이며, 데모 용도로만 사용
_EQ5D_KR_DEMO_WEIGHTS = {
    "constant": 0.097,
    "MO": [0.0, 0.066, 0.108, 0.247, 0.327],
    "SC": [0.0, 0.044, 0.068, 0.180, 0.235],
    "UA": [0.0, 0.044, 0.077, 0.156, 0.215],
    "PD": [0.0, 0.054, 0.103, 0.255, 0.337],
    "AD": [0.0, 0.066, 0.118, 0.263, 0.357],
}


def score_eq5d(answers: dict) -> dict:
    """EQ-5D-5L Korean demo value set. 1=문제없음 → 0 disutility.
    실제 Kim 2016 가중치와는 다른 근사.
    """
    keys = ["eq_mobility", "eq_selfcare", "eq_usual", "eq_pain", "eq_anxiety"]
    code_keys = ["MO", "SC", "UA", "PD", "AD"]
    levels = []
    for k in keys:
        v = answers.get(k)
        if v is None:
            return {"index": None, "vas": answers.get("eq_vas"), "approx": True}
        levels.append(int(v))
    if all(L == 1 for L in levels):
        idx = 1.0
    else:
        idx = 1.0 - _EQ5D_KR_DEMO_WEIGHTS["constant"]
        for ck, L in zip(code_keys, levels):
            idx -= _EQ5D_KR_DEMO_WEIGHTS[ck][L - 1]
    return {
        "index": round(idx, 3),
        "vas": answers.get("eq_vas"),
        "profile": "".join(str(L) for L in levels),
        "approx": True,
        "note": "데모 근사 가중치. 정식 Kim 2016 value set 적용 필요.",
    }


SCORING_FNS = {
    "CLDQ_NASH_KOR_DEMO": score_cldq,
    "FACIT_FATIGUE_KOR": score_facit_fatigue,
    "PROMIS_FATIGUE_KOR_SF8A": score_promis_fatigue,
    "HEPATIC_ITCH_NRS": score_itch,
    "EQ5D5L_KOR": score_eq5d,
}


def score_entry(scale_id: str, answers: dict) -> dict:
    fn = SCORING_FNS.get(scale_id)
    if not fn:
        return {"error": f"unknown scale {scale_id}"}
    return fn(answers)


def all_scale_summaries() -> list:
    """README 및 dashboard에 보여줄 요약."""
    out = []
    for s in ALL_SCALES:
        out.append({
            "id": s["id"],
            "name_kr": s["name_kr"],
            "n_items": len(s["items"]),
            "validation_level": s["validation_status"]["level"],
            "validation_label": s["validation_status"]["label"],
        })
    return out


if __name__ == "__main__":
    import json
    print(json.dumps(all_scale_summaries(), ensure_ascii=False, indent=2))
