"""CUSUM detector — TDD against the Rust ml-regime/cusum.rs algorithm (two-sided, σ-unit drift/threshold)."""
from __future__ import annotations

from fxhnt.domain.regime import CusumDetector


def _detector() -> CusumDetector:
    return CusumDetector(target_mean=0.0, target_std=1.0, drift_allowance=0.5, detection_threshold=5.0)


def test_stable_series_no_break() -> None:
    d = _detector()
    assert all(d.update(0.0) is None for _ in range(100))     # at target, drift keeps sums at 0
    assert d.positive_sum == 0.0 and d.negative_sum == 0.0


def test_upward_shift_detected() -> None:
    d = _detector()
    # 3σ jumps: S⁺ grows by 2.5 each step (3 − 0.5) → crosses 5 on the 3rd update (2.5, 5.0, 7.5)
    assert d.update(3.0) is None      # S⁺ = 2.5
    assert d.update(3.0) is None      # S⁺ = 5.0 (not > 5)
    brk = d.update(3.0)               # S⁺ = 7.5 > 5
    assert brk is not None and brk.direction == "positive"
    assert abs(brk.magnitude - 7.5) < 1e-9 and brk.magnitude > 0
    assert brk.observations_since_reset == 3


def test_downward_shift_has_negative_magnitude() -> None:
    d = _detector()
    brk = None
    for _ in range(3):
        brk = d.update(-3.0)
    assert brk is not None and brk.direction == "negative"
    assert abs(brk.magnitude + 7.5) < 1e-9 and brk.magnitude < 0


def test_reset_clears_state() -> None:
    d = _detector()
    for _ in range(3):
        d.update(3.0)
    d.reset()
    assert d.positive_sum == 0.0 and d.negative_sum == 0.0
    assert d.update(0.0) is None
