"""Bias direction taxonomy + discordance 진단 + bariatric preference-based IV.

Munafò 2018 triangulation에서 강조된 바와 같이,
discordance가 있을 때 각 design의 예상 bias 방향을 알아야
어느 추정치가 진실에 가까운지 판단 가능하다.
"""
from __future__ import annotations

import math
from typing import Dict, List, Optional

# bias direction taxonomy: (design, bias_type) → expected direction on effect estimate
# (+: overestimate harm/protective magnitude; -: underestimate; ?: depends)
BIAS_TAXONOMY = {
    "observational": [
        ("confounding_by_indication", "?",
         "고위험 환자에 처방 → 위험 과대; 또는 healthy initiator → 보호효과 과대"),
        ("healthy_user", "+protect",
         "약물 복용 환자가 더 건강 행동 → 보호효과 과대"),
        ("detection_bias", "+harm",
         "GLP-1RA 복용자 더 자주 검진 → 갑상선 결절 detection ↑"),
        ("protopathic", "+harm",
         "초기 미진단 증상으로 약물 처방 → 약물 유발 외양"),
        ("immortal_time", "+protect",
         "처방 이전 생존 시간을 노출에 할당 → 보호효과 과대"),
    ],
    "RCT": [
        ("external_validity", "?",
         "선택된 인구집단 (low-risk, 단기) → real world와 다름"),
        ("dose_translation", "?",
         "최대 용량 사용 vs RWE의 underdosing"),
        ("loss_to_followup", "?", "differential dropout"),
    ],
    "BMI_MR": [
        ("canalization", "-",
         "평생 BMI 노출 → 단기 의사 개입과 다른 effect"),
        ("pleiotropy", "?",
         "BMI variant가 다른 경로로 영향 → MR-Egger sensitivity 필요"),
        ("collider_bias_BMI_selection", "?",
         "UK Biobank 등 자가선택 → BMI 분포 좌측화"),
    ],
    "multivariable_MR": [
        ("instrument_overlap_BMI_WHR", "+protect",
         "BMI/WHR/BF% IV correlated → conditional effect 추정 불안정"),
        ("weak_instrument_conditional", "?", "F-statistic <10 in MVMR"),
    ],
    "bariatric_natural": [
        ("selection_bias_surgical_candidate", "+protect",
         "수술 환자가 더 동기/건강 → 보호효과 과대 (preference-based IV로 부분 해결)"),
        ("immortal_time_post_surgery", "+protect",
         "수술 직후 30d 사망 제외 → 보호효과 과대"),
        ("center_effect", "?", "고용량 센터 vs 저용량 센터"),
    ],
    "within_subject_crossover": [
        ("carryover_effect", "?", "washout 부족"),
        ("period_effect", "?", "계절/시점 차이"),
        ("small_sample", "+random",
         "n<200 → 추정치 불안정"),
    ],
    "DIO_animal": [
        ("species_extrapolation", "?", "마우스 GLP-1R vs 인간"),
        ("dose_translation_animal", "+harm or +protect",
         "mg/kg → 인간 등가용량 환산 오류"),
        ("weight_matched_control_artifact", "-",
         "단기 weight-matching이 long-term 효과 미반영"),
    ],
}


def diagnose_discordance(intervention: str, outcome: str) -> Dict:
    """6-design grid에서 design별 bias 방향을 진단하고
    어느 추정치가 진실에 가까운지 ranking."""
    from .grid import get_pair_rows, _to_float, concordance_score, direction
    rows = get_pair_rows(intervention, outcome)
    if not rows:
        return {"error": "no data", "intervention": intervention, "outcome": outcome}

    conc = concordance_score(rows)
    if conc["direction_agreement"] is None or conc["direction_agreement"] >= 0.85:
        return {
            "intervention": intervention,
            "outcome": outcome,
            "discordant": False,
            "concordance": conc,
            "note": "방향 일치 충분, discordance 미진단 필요 없음",
        }

    diagnoses = []
    for r in rows:
        est = _to_float(r["effect_estimate"])
        if est is None:
            continue
        d = direction(est)
        design_biases = BIAS_TAXONOMY.get(r["design"], [])
        diagnoses.append({
            "design": r["design"],
            "estimate": est,
            "direction": {-1: "protect", 0: "null", 1: "harm"}[d],
            "potential_biases": [
                {"type": b[0], "expected_direction": b[1], "note": b[2]}
                for b in design_biases
            ],
        })

    # priority ranking: RCT > MVMR > bariatric_natural > BMI_MR > observational > crossover > animal
    priority = {"RCT": 1, "multivariable_MR": 2, "bariatric_natural": 3,
                "BMI_MR": 4, "observational": 5, "within_subject_crossover": 6, "DIO_animal": 7}
    diagnoses.sort(key=lambda x: priority.get(x["design"], 99))

    return {
        "intervention": intervention,
        "outcome": outcome,
        "discordant": True,
        "concordance": conc,
        "diagnoses": diagnoses,
        "recommendation": (
            "1) RCT 추정치를 anchor로 사용. "
            "2) Observational이 더 큰 효과면 healthy-user/immortal-time 의심. "
            "3) MR이 RCT보다 작으면 short-term pharmacological effect ≠ lifetime BMI exposure (canalization). "
            "4) Bariatric > RCT면 selection bias for surgery candidate 보정 필요 (preference-based IV)."
        ),
    }


def bariatric_iv_sensitivity(
    intervention: str,
    outcome: str,
    bariatric_OR: float,
    rct_OR: Optional[float] = None,
    preference_iv_strength: float = 0.6,
) -> Dict:
    """Preference-based IV (center-level bariatric preference)를 활용한 sensitivity.

    가정: center별 bariatric vs medical management 선호도가 결과의
    confounder와 무관(IV 가정). preference_iv_strength = first-stage F를
    상수 0.6 (전형적 60% 변동) 가정.

    2SLS ratio estimator: IV_effect = reduced_form / first_stage_strength
    """
    if bariatric_OR is None or bariatric_OR <= 0:
        return {"error": "invalid bariatric_OR"}
    iv_log = math.log(bariatric_OR) / preference_iv_strength
    iv_OR = math.exp(iv_log)
    selection_bias_pct = None
    if rct_OR and rct_OR > 0:
        selection_bias_pct = (
            (math.log(bariatric_OR) - math.log(rct_OR)) / math.log(rct_OR) * 100
            if abs(math.log(rct_OR)) > 1e-6 else None
        )
    return {
        "intervention": intervention,
        "outcome": outcome,
        "naive_bariatric_OR": bariatric_OR,
        "preference_IV_corrected_OR": round(iv_OR, 3),
        "iv_strength_assumed": preference_iv_strength,
        "rct_OR_for_comparison": rct_OR,
        "estimated_selection_bias_pct": round(selection_bias_pct, 1) if selection_bias_pct else None,
        "interpretation": (
            "Preference-based IV 보정 후 효과가 RCT와 가까워지면 selection bias가 주된 원인. "
            "여전히 큰 차이가 남으면 surgery만의 unique mechanism (incretin axis remodeling) 시사."
        ),
    }


if __name__ == "__main__":
    print(diagnose_discordance("intermittent_fasting", "CV death"))
    print()
    print(bariatric_iv_sensitivity("bariatric_RYGB", "all_cause_mortality",
                                    bariatric_OR=0.70, rct_OR=0.75))
