"""PancIsletMass v0 — β-cell mass 산정 (Cavalieri systematic random sampling).

β-cell mass (mg) = (Σ β-cell area / Σ pancreas section area) × pancreas weight (mg)

각 슬라이드는 동일 절편 두께·등간격 절단의 systematic random sample이라 가정
(Cavalieri principle). 픽셀 → μm² 변환은 image_um_per_px 사용.
"""

from __future__ import annotations

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

import numpy as np


@dataclass
class SlideMassRecord:
    slide_id: str
    group: str
    mouse_id: str
    pancreas_weight_mg: float
    image_um_per_px: float
    pancreas_section_area_um2: float
    beta_area_um2: float
    alpha_area_um2: float
    delta_area_um2: float
    beta_fraction: float


def slide_record(
    *,
    slide_id: str,
    group: str,
    mouse_id: str,
    pancreas_weight_mg: float,
    image_um_per_px: float,
    section_area_px: int,
    beta_px: int,
    alpha_px: int,
    delta_px: int,
) -> SlideMassRecord:
    px2 = float(image_um_per_px) ** 2
    sec_um2 = float(section_area_px) * px2
    b_um2 = float(beta_px) * px2
    a_um2 = float(alpha_px) * px2
    d_um2 = float(delta_px) * px2
    endo = b_um2 + a_um2 + d_um2
    bf = (b_um2 / endo) if endo > 0 else 0.0
    return SlideMassRecord(
        slide_id=slide_id,
        group=group,
        mouse_id=mouse_id,
        pancreas_weight_mg=float(pancreas_weight_mg),
        image_um_per_px=float(image_um_per_px),
        pancreas_section_area_um2=sec_um2,
        beta_area_um2=b_um2,
        alpha_area_um2=a_um2,
        delta_area_um2=d_um2,
        beta_fraction=bf,
    )


def mouse_beta_mass_mg(records: Iterable[SlideMassRecord]) -> Dict:
    """Cavalieri-style aggregation across one mouse's slides.

    Returns dict with: mouse_id, group, pancreas_weight_mg, beta_fraction,
    beta_mass_mg, n_slides.
    """
    recs = list(records)
    if not recs:
        return {}
    mouse_id = recs[0].mouse_id
    group = recs[0].group
    pw = recs[0].pancreas_weight_mg
    sum_beta = sum(r.beta_area_um2 for r in recs)
    sum_sec = sum(r.pancreas_section_area_um2 for r in recs)
    bf = (sum_beta / sum_sec) if sum_sec > 0 else 0.0
    return {
        "mouse_id": mouse_id,
        "group": group,
        "pancreas_weight_mg": pw,
        "n_slides": len(recs),
        "beta_fraction": round(bf, 5),
        "beta_mass_mg": round(bf * pw, 4),
    }


def cohort_summary(records_by_mouse: Dict[str, List[SlideMassRecord]]) -> List[Dict]:
    out: List[Dict] = []
    for mouse_id, recs in records_by_mouse.items():
        agg = mouse_beta_mass_mg(recs)
        if agg:
            out.append(agg)
    return out
