"""Weight-loss-mediated vs weight-loss-independent 분리.

VanderWeele 4-way decomposition (TNDE+PNDE+TNIE+PNIE)을
2-way mediated/direct로 단순화한 product-of-coefficient & difference methods.
"""
from __future__ import annotations

import math
from typing import Dict, Optional


def product_of_coefficients(
    intervention_to_weightloss: float,
    weightloss_to_outcome: float,
) -> float:
    """log-scale에서 매개효과 = α × β."""
    return intervention_to_weightloss * weightloss_to_outcome


def difference_method(
    total_log_effect: float,
    direct_log_effect: float,
) -> float:
    """매개효과 = total - direct (log-scale)."""
    return total_log_effect - direct_log_effect


def weight_loss_mediated_fraction(
    total_OR: float,
    direct_OR: Optional[float] = None,
    intervention_pct_weightloss: Optional[float] = None,
    weightloss_to_outcome_OR_per_5pct: Optional[float] = None,
) -> Dict:
    """매개 비율 (mediated fraction) 추정.

    두 가지 경로:
    a) direct effect를 active comparator new-user 디자인에서 추정한 경우 → difference method.
    b) intervention→weight_loss 효과 (kg or %) + weight_loss→outcome 효과 (BMI MR proxy) →
       product-of-coefficient method.
    """
    if total_OR is None or total_OR <= 0:
        return {"error": "invalid total_OR"}
    total_log = math.log(total_OR)

    result = {"total_OR": total_OR, "total_log": round(total_log, 4)}

    if direct_OR is not None and direct_OR > 0:
        direct_log = math.log(direct_OR)
        mediated_log = difference_method(total_log, direct_log)
        mediated_frac = mediated_log / total_log if abs(total_log) > 1e-6 else 0.0
        result.update({
            "method": "difference",
            "direct_OR": direct_OR,
            "mediated_log": round(mediated_log, 4),
            "mediated_fraction": round(max(0.0, min(1.0, mediated_frac)), 3),
            "direct_fraction": round(max(0.0, min(1.0, 1 - mediated_frac)), 3),
        })
        return result

    if (intervention_pct_weightloss is not None
            and weightloss_to_outcome_OR_per_5pct is not None
            and weightloss_to_outcome_OR_per_5pct > 0):
        units = intervention_pct_weightloss / 5.0
        mediated_log = units * math.log(weightloss_to_outcome_OR_per_5pct)
        mediated_frac = mediated_log / total_log if abs(total_log) > 1e-6 else 0.0
        result.update({
            "method": "product_of_coefficients",
            "intervention_pct_weightloss": intervention_pct_weightloss,
            "weightloss_to_outcome_OR_per_5pct": weightloss_to_outcome_OR_per_5pct,
            "mediated_log": round(mediated_log, 4),
            "mediated_fraction": round(max(0.0, min(1.0, mediated_frac)), 3),
            "direct_fraction": round(max(0.0, min(1.0, 1 - mediated_frac)), 3),
        })
        return result

    result["error"] = "insufficient input for mediation"
    return result


def mediation_for_pair(intervention: str, outcome: str) -> Dict:
    """grid 데이터에서 매개 분석.

    weight_loss_mediated_pct가 큐레이션된 경우 그대로 사용,
    추가로 BMI_MR + RCT로 product method 비교.
    """
    from .grid import get_pair_rows, _to_float
    from .ontology import load_interventions

    rows = get_pair_rows(intervention, outcome)
    if not rows:
        return {"error": "no data", "intervention": intervention, "outcome": outcome}

    # 큐레이션된 mediated_pct (RCT 우선)
    rct_row = next((r for r in rows if r["design"] == "RCT"), None)
    bmi_mr = next((r for r in rows if r["design"] == "BMI_MR"), None)

    if rct_row is None:
        return {"error": "no RCT for mediation", "intervention": intervention, "outcome": outcome}

    total_OR = _to_float(rct_row["effect_estimate"])
    curated_mediated_pct = _to_float(rct_row.get("weight_loss_mediated_pct"))

    # intervention의 typical weight loss (%)
    ivs = load_interventions()
    iv_meta = next((i for i in ivs if i["intervention"] == intervention), None)
    typical_wl = _to_float(iv_meta["typical_weight_loss_pct"]) if iv_meta else None

    # BMI_MR 효과: per BMI unit → per 5% weight loss로 변환 가정
    # 보수적: BMI 1 unit ≈ 3% body weight
    weightloss_5pct_OR = None
    if bmi_mr:
        bmi_or = _to_float(bmi_mr["effect_estimate"])
        if bmi_or and bmi_or > 0:
            # log(OR per BMI unit) → log(OR per 5% weight) ≈ log(OR) × 5/3
            weightloss_5pct_OR = math.exp(math.log(bmi_or) * (5.0 / 3.0))

    product_result = None
    if total_OR and typical_wl and weightloss_5pct_OR:
        product_result = weight_loss_mediated_fraction(
            total_OR=total_OR,
            intervention_pct_weightloss=typical_wl,
            weightloss_to_outcome_OR_per_5pct=weightloss_5pct_OR,
        )

    return {
        "intervention": intervention,
        "outcome": outcome,
        "total_OR_RCT": total_OR,
        "curated_mediated_pct": curated_mediated_pct,
        "typical_weight_loss_pct": typical_wl,
        "implied_OR_per_5pct_weightloss": round(weightloss_5pct_OR, 3) if weightloss_5pct_OR else None,
        "product_method": product_result,
        "interpretation": (
            f"체중감소 매개 비율 ≈ {curated_mediated_pct}% (curated). "
            f"product-of-coefficient = {product_result['mediated_fraction'] if product_result and 'mediated_fraction' in product_result else 'N/A'}. "
            "두 추정치가 ±15%p 이내면 weight-loss mediated 강력, "
            "차이가 크면 direct effect (예: GLP-1R neural/cardiac) 의심."
        ),
    }


if __name__ == "__main__":
    print(mediation_for_pair("semaglutide", "CV death"))
    print(mediation_for_pair("tirzepatide", "sarcopenia"))
    print(mediation_for_pair("bariatric_RYGB", "hip_fracture"))
