"""Triangulation-targeted 후속 가설 + 8가지 design 카드.

discordance/missing-design 갭에 따라 다음 design 8종 중 최적 추천:
1. Active comparator new-user (target trial emulation)
2. Multivariable MR (BMI + WHR + body fat %)
3. Negative control outcome / negative control exposure
4. 2×2 factorial (예: GLP-1RA × exercise)
5. Within-subject crossover
6. Bariatric preference-based IV
7. DIO animal weight-matched control
8. Mediation N-of-1 / E-N-of-1
"""
from __future__ import annotations

from typing import Dict, List


def design_card(design_type: str, intervention: str, outcome: str,
                rationale: str) -> Dict:
    """후속 design 카드 1개 생성."""
    templates = {
        "active_comparator_new_user": {
            "primary_endpoint": "3P-MACE / outcome 특이",
            "sample_size_estimate": "n=10,000~50,000 (claims/EHR)",
            "follow_up_years": "2~5",
            "key_hypothesis": (
                f"{intervention} vs DPP-4i (active comparator) new-user "
                f"propensity-matched analysis로 confounding by indication 최소화."
            ),
            "multivariable_MR_instruments": "N/A (real-world emulation)",
            "key_threats": "residual unmeasured confounding (체중·HbA1c)",
            "minimum_data": "처방 시작일·index date·comorbidity·BMI",
        },
        "multivariable_MR_BMI_WHR_BF": {
            "primary_endpoint": "outcome OR per SD adiposity phenotype",
            "sample_size_estimate": "n=500,000 (UK Biobank, FinnGen, KoGES)",
            "follow_up_years": "lifetime exposure",
            "key_hypothesis": (
                f"BMI, WHR, body fat % 동시 IV로 {intervention}이 영향 주는 "
                f"adiposity 표현형을 conditional 분리하여 {outcome} 효과의 "
                f"adipose-distribution-specific contribution 추정."
            ),
            "multivariable_MR_instruments": (
                "GIANT BMI 941 SNP, UK Biobank WHR 346 SNP, body fat % 425 SNP. "
                "MVMR-Egger / MVMR-IVW / MR-PRESSO sensitivity."
            ),
            "key_threats": "weak instrument bias (conditional F<10), horizontal pleiotropy",
            "minimum_data": "GWAS summary stats + outcome GWAS",
        },
        "negative_control_outcome": {
            "primary_endpoint": "결과와 무관한 outcome (예: 사고사)",
            "sample_size_estimate": "동일 cohort 활용",
            "follow_up_years": "동일",
            "key_hypothesis": (
                f"{intervention} 처방자의 사고사·교통사고 등 "
                "biology-unrelated outcome에 'effect'가 있으면 healthy-user bias 시사."
            ),
            "multivariable_MR_instruments": "N/A",
            "key_threats": "negative control 선택의 misspecification",
            "minimum_data": "outcome 분류 ICD",
        },
        "factorial_2x2": {
            "primary_endpoint": "체성분·outcome composite",
            "sample_size_estimate": "n=400~1,200",
            "follow_up_years": "1~2",
            "key_hypothesis": (
                f"{intervention} × resistance exercise 2×2 factorial로 "
                "sarcopenia/lean mass loss를 운동이 부분 상쇄하는지 검증. "
                "interaction term 통계적 유의성."
            ),
            "multivariable_MR_instruments": "N/A",
            "key_threats": "adherence (특히 운동 군)",
            "minimum_data": "DXA, 6MWT, grip strength",
        },
        "within_subject_crossover": {
            "primary_endpoint": "단기 surrogate (HbA1c, BP, 체중)",
            "sample_size_estimate": "n=60~200",
            "follow_up_years": "0.5~1",
            "key_hypothesis": (
                f"on-{intervention}/off-{intervention} 4기 crossover로 "
                "individual-level treatment effect 분포 추정."
            ),
            "multivariable_MR_instruments": "N/A",
            "key_threats": "carryover (GLP-1 long t1/2), period bias",
            "minimum_data": "high-frequency biomarker",
        },
        "bariatric_preference_IV": {
            "primary_endpoint": outcome,
            "sample_size_estimate": "n>5,000 multi-center",
            "follow_up_years": "5~20",
            "key_hypothesis": (
                "center-level bariatric vs medical 선호도를 IV로 활용, "
                f"{intervention} (bariatric)의 conditional effect를 selection bias 보정 후 추정."
            ),
            "multivariable_MR_instruments": "preference-IV first-stage F>10 필요",
            "key_threats": "IV exclusion 위반 (center가 다른 영향)",
            "minimum_data": "multi-center cohort, center ID, outcome",
        },
        "DIO_animal_weight_matched": {
            "primary_endpoint": "tissue-specific (간·근·뇌·심)",
            "sample_size_estimate": "n=80~150 mice",
            "follow_up_years": "0.2~0.6",
            "key_hypothesis": (
                f"DIO mouse에 {intervention} vs vehicle + pair-fed weight-matched control로 "
                "weight-independent direct effect (GLP-1R 신경/심장) 분리."
            ),
            "multivariable_MR_instruments": "N/A",
            "key_threats": "species extrapolation, pair-feeding stress",
            "minimum_data": "tissue histology, RNA-seq",
        },
        "mediation_N_of_1": {
            "primary_endpoint": "individual mediated/direct decomposition",
            "sample_size_estimate": "n=1 × multiple periods",
            "follow_up_years": "0.5~1",
            "key_hypothesis": (
                f"단일 환자에서 {intervention} dose adjustment으로 "
                "weight loss와 outcome 변화의 individual mediation 추정."
            ),
            "multivariable_MR_instruments": "N/A",
            "key_threats": "single subject 일반화 불가",
            "minimum_data": "CGM/wearable, weekly biomarker",
        },
    }
    t = templates.get(design_type, {})
    return {
        "type": design_type,
        "intervention": intervention,
        "outcome": outcome,
        "rationale": rationale,
        **t,
    }


def recommend_designs(intervention: str, outcome: str) -> List[Dict]:
    """현재 데이터의 갭에 따라 8 design 중 우선순위 추천."""
    from .grid import get_pair_rows
    rows = get_pair_rows(intervention, outcome)
    have = set(r["design"] for r in rows)

    recommendations = []
    # RCT 없으면 active comparator
    if "RCT" not in have:
        recommendations.append(design_card(
            "active_comparator_new_user", intervention, outcome,
            "RCT가 없거나 비실현적인 outcome → target trial emulation 우선."
        ))
    # MVMR 없으면 추천
    if "multivariable_MR" not in have:
        recommendations.append(design_card(
            "multivariable_MR_BMI_WHR_BF", intervention, outcome,
            "BMI MR만 있고 WHR/BF% 분리 없음 → adiposity 표현형 contribution 추정 필요."
        ))
    # observational discordant이거나 missing
    if "observational" in have:
        recommendations.append(design_card(
            "negative_control_outcome", intervention, outcome,
            "Observational 효과가 RCT보다 크면 healthy-user bias 검증 필요."
        ))
    # bariatric 큰 효과
    if any("bariatric" in r["intervention"] for r in rows) and "bariatric_natural" in have:
        recommendations.append(design_card(
            "bariatric_preference_IV", intervention, outcome,
            "Bariatric vs medical comparison에서 selection bias 보정."
        ))
    # sarcopenia/lean mass outcome
    if outcome.lower() in ("sarcopenia", "hip_fracture", "osteoarthritis"):
        recommendations.append(design_card(
            "factorial_2x2", intervention, outcome,
            "Lean mass loss를 운동이 mitigate하는지 factorial로 검증."
        ))
    # DIO animal 없으면
    if "DIO_animal" not in have:
        recommendations.append(design_card(
            "DIO_animal_weight_matched", intervention, outcome,
            "Weight-independent direct effect 분리 위해 pair-fed control 필요."
        ))
    # within-subject 없으면
    if "within_subject_crossover" not in have:
        recommendations.append(design_card(
            "within_subject_crossover", intervention, outcome,
            "Individual-level treatment effect heterogeneity 평가."
        ))
    # mediation N-of-1
    recommendations.append(design_card(
        "mediation_N_of_1", intervention, outcome,
        "Personalized mediation: dose adjustment → mediated/direct fraction."
    ))
    return recommendations[:8]


if __name__ == "__main__":
    cards = recommend_designs("semaglutide", "CV death")
    for c in cards:
        print(c["type"], "—", c["rationale"][:80])
