"""_reject_outlier_drops -- the outlier-rejection pass in the battery
remaining-time estimate (see routers/common.py's battery_estimate_s).
Pure function, no DB/HTTP -- (recency_weight, drop_pct) pairs in,
filtered pairs out."""

from __future__ import annotations

from app.routers.common import _reject_outlier_drops


def _steps(drops: list[float]) -> list[tuple[int, float]]:
    return [(i + 1, d) for i, d in enumerate(drops)]


def _avg(steps: list[tuple[int, float]]) -> float:
    total_weight = sum(w for w, _ in steps)
    return sum(w * d for w, d in steps) / total_weight


def test_no_outlier_keeps_every_step():
    steps = _steps([1, 1, 2, 1, 1, 2, 1])
    assert _reject_outlier_drops(steps) == steps


def test_single_glitch_dip_is_rejected():
    """The exact shape reported in production: 18 ordinary 1%-per-wake
    steps and one spliced-in 26% glitch -- the naive median-based MAD
    degenerates to 0 here (more than half the steps tie at the median),
    which used to let the glitch sail straight through untouched."""
    normal = [1] * 18
    glitchy = normal[:9] + [26] + normal[9:]

    kept = _reject_outlier_drops(_steps(glitchy))
    kept_drops = [d for _, d in kept]
    assert 26 not in kept_drops
    assert len(kept) == 18

    # the whole point: the estimate should come out the same as if the
    # glitch had never been recorded at all
    baseline_avg = _avg(_steps(normal))
    filtered_avg = _avg(kept)
    assert abs(filtered_avg - baseline_avg) < 1e-9


def test_single_glitch_spike_is_rejected():
    normal = [2] * 18
    glitchy = normal[:5] + [40] + normal[5:]

    kept = _reject_outlier_drops(_steps(glitchy))
    kept_drops = [d for _, d in kept]
    assert 40 not in kept_drops
    assert len(kept) == 18


def test_identical_steps_reject_nothing():
    """Every step tied at the exact same value -- both the median MAD
    and the mean-absolute-deviation fallback are 0 here, which is the
    one case _reject_outlier_drops explicitly bails out of rather than
    filtering down to nothing."""
    steps = _steps([1] * 10)
    assert _reject_outlier_drops(steps) == steps


def test_never_filters_down_to_nothing():
    """Even a genuinely bimodal series (half the wakes cheap, half
    expensive -- not a single-glitch shape at all) shouldn't empty the
    list; a battery_estimate_s caller treats an empty result as
    "insufficient data," which a merely-noisy history isn't."""
    steps = _steps([1, 1, 1, 1, 10, 10, 10, 10])
    kept = _reject_outlier_drops(steps)
    assert len(kept) > 0
