"""Tests from Capstone B's real release reports. Run: pytest test_release_practice.py"""
import math

from release_practice import (canary_decision, clips_needed, probe_alarms, signal_alarm,
                              smallest_detectable)

WPS = dict(margin=0.25, relative=True, both_ways=True)


def test_identical_rebuild_noise_passes_the_margin_but_not_the_z():
    # base-rebuild, seed 3, check 3: contact-centre words/s 1.984 -> 2.635 (+33%), z = 3.0
    assert signal_alarm(1.984, 2.635, 3.0, **WPS) is False
    # with a looser z line, the same noise would have rolled back an identical rebuild
    assert signal_alarm(1.984, 2.635, 3.0, z_line=2.5, **WPS) is True


def test_decoder_bug_moves_the_signals_but_six_requests_are_not_enough():
    # base-newdecoder, check 1: 2 of 6 contact-centre canary requests empty (4% on stable)
    assert signal_alarm(0.042, 0.333, 2.13, margin=0.05) is False
    # words/s fell 58%, but z = -1.49
    assert signal_alarm(3.27, 1.382, -1.49, **WPS) is False
    # the same change with the evidence of more requests would alarm, in either direction
    assert signal_alarm(3.27, 1.382, -4.0, **WPS) is True
    assert signal_alarm(0.042, 0.333, 4.0, margin=0.05) is True
    # but an empty rate that falls is good news, however strong the evidence
    assert signal_alarm(0.10, 0.01, -5.0, margin=0.05) is False
    assert signal_alarm(0.0, 0.0, 9.9, margin=0.05, relative=True) is False


def test_probes():
    assert probe_alarms(9.2, 31.6, ["1284-1181-0002"]) == ["probe WER", "must-pass"]
    assert probe_alarms(9.2, 9.2, []) == []
    # small-v2: better on the probes, no alarm
    assert probe_alarms(9.2, 6.1, []) == []


def test_canary_decisions():
    # the decoder: first check, 30 canary requests, three alarms
    alarms = ["impossible event", "probe WER", "must-pass"]
    assert canary_decision(alarms, {"podcasts": 11, "contact_center": 6, "earnings": 13}, 108) == "rollback"
    # a rebuild halfway: no alarm, not enough evidence yet
    assert canary_decision([], {"podcasts": 32, "contact_center": 28, "earnings": 32}, 332) == "continue"
    # small-v2 at its 5th check
    assert canary_decision([], {"podcasts": 42, "contact_center": 51, "earnings": 57}, 612) == "promote"
    # no evidence, no release
    assert canary_decision([], {"podcasts": 300, "contact_center": 300, "earnings": 12}, 900) == "rollback"


def test_what_the_phone_gate_can_see():
    # voxbench-v1: 60 phone clips, a ±4.7-point interval on a paired difference
    d = smallest_detectable(4.7)
    assert math.isclose(d, 6.7, abs_tol=0.05)
    # to see the gate's own 1.5-point tolerance: on the order of 1,200 clips
    assert 1100 < clips_needed(60, 6.8, 1.5) < 1300
    # read: 120 clips, ±1.4 -> about 2 points, needs about 4x the clips for 1.0
    assert math.isclose(smallest_detectable(1.4), 2.0, abs_tol=0.05)
    assert math.isclose(clips_needed(120, 1.9, 1.0), 433.2, abs_tol=0.1)
