"""post-bariatric hypoglycemia + dumping syndrome 시간 분포 분석.

Time buckets:
  - POD0_3   : immediate hypoglycemia (perioperative)
  - POD4_30  : dumping early/late, transition
  - POD30_90 : delayed post-prandial hyperinsulinemic (PBH classic)

Severity (KDA hypoglycemia guide):
  - L1 : 54-69 mg/dL  (alert)
  - L2 : <54 mg/dL    (clinically significant)
  - L3 : severe needing 3rd-party assistance

Output:
  - distribution by time bucket x hypo_type
  - per-procedure event rate
  - severity mix
  - KDA-guide flag rows (level 2+ requiring action)
"""
from __future__ import annotations

from dataclasses import dataclass
from typing import Dict, List, Tuple

from .ingest import HypoEvent, Patient


@dataclass
class HypoBucketRow:
    time_bucket: str          # POD0_3 / POD4_30 / POD30_90
    hypo_type: str            # immediate / delayed_postprandial / dumping_early/late
    n_events: int
    n_unique_patients: int
    mean_glucose: float
    pct_L2_or_worse: float
    kda_action_recommended: bool


@dataclass
class HypoByProcedureRow:
    procedure: str
    n_patients: int
    n_immediate_events: int
    n_delayed_events: int
    n_dumping_events: int
    immediate_rate_pct: float    # events per patient *100
    delayed_rate_pct: float
    dumping_rate_pct: float


def _avg(xs):
    return round(sum(xs) / len(xs), 1) if xs else 0.0


def time_distribution(hypo: List[HypoEvent]) -> List[HypoBucketRow]:
    grp: Dict[Tuple[str, str], List[HypoEvent]] = {}
    for ev in hypo:
        grp.setdefault((ev.time_bucket, ev.hypo_type), []).append(ev)

    out: List[HypoBucketRow] = []
    for (bucket, htype), events in sorted(grp.items()):
        if not events:
            continue
        gluc = [e.glucose_mg_dl for e in events]
        n_l2 = sum(1 for e in events if e.severity in ("L2", "L3"))
        n_unique = len({e.patient_id for e in events})
        rate_l2 = round(100.0 * n_l2 / len(events), 1)
        kda_flag = (rate_l2 >= 20.0)
        out.append(HypoBucketRow(
            time_bucket=bucket, hypo_type=htype,
            n_events=len(events), n_unique_patients=n_unique,
            mean_glucose=_avg(gluc),
            pct_L2_or_worse=rate_l2,
            kda_action_recommended=kda_flag,
        ))
    return out


def by_procedure(patients: List[Patient],
                 hypo: List[HypoEvent]) -> List[HypoByProcedureRow]:
    proc_of: Dict[str, str] = {p.patient_id: p.procedure for p in patients}
    n_proc: Dict[str, int] = {}
    for p in patients:
        n_proc[p.procedure] = n_proc.get(p.procedure, 0) + 1

    counts: Dict[str, Dict[str, int]] = {
        proc: {"imm": 0, "delay": 0, "dump": 0} for proc in n_proc
    }
    for ev in hypo:
        proc = proc_of.get(ev.patient_id)
        if not proc:
            continue
        if ev.hypo_type == "immediate":
            counts[proc]["imm"] += 1
        elif ev.hypo_type == "delayed_postprandial":
            counts[proc]["delay"] += 1
        elif ev.hypo_type.startswith("dumping"):
            counts[proc]["dump"] += 1

    out: List[HypoByProcedureRow] = []
    for proc, n in sorted(n_proc.items()):
        c = counts[proc]
        out.append(HypoByProcedureRow(
            procedure=proc,
            n_patients=n,
            n_immediate_events=c["imm"],
            n_delayed_events=c["delay"],
            n_dumping_events=c["dump"],
            immediate_rate_pct=round(100.0 * c["imm"] / n, 2) if n else 0.0,
            delayed_rate_pct=round(100.0 * c["delay"] / n, 2) if n else 0.0,
            dumping_rate_pct=round(100.0 * c["dump"] / n, 2) if n else 0.0,
        ))
    return out


def kda_guide_flags(hypo: List[HypoEvent]) -> List[HypoEvent]:
    """Return only level-2+ events (KDA action required)."""
    return [e for e in hypo if e.severity in ("L2", "L3")]
