"""Tests from Lab 07's real results. Run: pytest test_gates_practice.py"""
from gates_practice import exit_code, must_pass, no_new_failures, relative_verdict


def test_relative_blocks_a_real_regression_beyond_tolerance():
    # whisper-tiny.en on read speech, full tier: +3.31 (+1.11 to +5.62), tolerance 1.0
    assert relative_verdict(3.31, 1.11, 5.62, 1.0) == "fail"


def test_relative_reports_a_real_loss_within_tolerance():
    # drop_1pct on read: +0.71 (+0.12 to +1.47), tolerance 1.0
    assert relative_verdict(0.71, 0.12, 1.47, 1.0) == "within"
    # drop_2pct_phone on phone: +1.18 (+0.58 to +1.85), tolerance 1.5
    assert relative_verdict(1.18, 0.58, 1.85, 1.5) == "within"


def test_relative_cant_tell_is_not_a_block():
    # nova-3 on calls: +4.11, but the interval (-3.29 to +15.23) includes zero
    assert relative_verdict(4.11, -3.29, 15.23, 1.5) == "unclear"


def test_relative_noise_above_tolerance_does_not_block():
    # A/A, API model, phone: pure noise reached +1.78; the interval kept the gate quiet
    assert relative_verdict(1.78, -0.40, 4.10, 1.5) == "unclear"


def test_relative_better():
    # whisper-small.en on read: -1.89 (-3.87 to -0.32)
    assert relative_verdict(-1.89, -3.87, -0.32, 1.0) == "better"


def test_bigger_model_blocked_without_netting():
    baseline = [{"dial-tone": "", "room-tone-b": "", "dtmf": "You", "hold-music-b": "You"}] * 5
    current = {"dial-tone": "You", "room-tone-b": "You", "dtmf": "", "hold-music-b": ""}
    assert no_new_failures(current, baseline) == ("fail", ["dial-tone", "room-tone-b"], ["dtmf", "hold-music-b"])


def test_a_flip_in_any_baseline_run_is_not_new():
    # distant talkers, three runs of the same local model: text / nothing / text
    runs = [{"distant-talkers": "We'll have our coffee."}, {"distant-talkers": ""},
            {"distant-talkers": "What would come? We'll have our coffee."}]
    status, new, _ = no_new_failures({"distant-talkers": "We'll have our coffee."}, runs)
    assert status == "pass" and new == []
    # with only the run that happened to be empty as the baseline, it looks new
    assert no_new_failures({"distant-talkers": "We'll have our coffee."}, [runs[1]])[0] == "fail"


def test_hallucination_that_wer_cannot_see():
    baseline = [{"clicks": "", "dial-tone": "", "room-tone-a": "You"}]
    current = {"clicks": "Thank you.", "dial-tone": "Thank you.", "room-tone-a": "You"}
    assert no_new_failures(current, baseline) == ("fail", ["clicks", "dial-tone"], [])


def test_must_pass_catches_one_word():
    assert must_pass("Net investments add up to around 10% capex to sales ratio.", "10% capex to sales ratio")
    assert not must_pass("Net investments add up to around 10% cabbage to sales ratio.", "10% capex to sales ratio")
    assert must_pass("The growth was 26.8%, ahead of plan.", "26.8%")


def test_must_pass_matches_whole_words():
    assert must_pass("Please turn to Page 24 of the deck.", "page 24")
    assert not must_pass("See pages 24 and 25.", "page 24")
    assert not must_pass("Turn to page 245.", "page 24")


def test_exit_codes():
    ok = [("pass", "block"), ("pass", "block")]
    assert exit_code(ok, []) == 0
    assert exit_code([("fail", "block"), ("pass", "warn")], []) == 1
    # latency more than doubled: a warn gate, so it never blocks
    assert exit_code([("pass", "block"), ("fail", "warn")], []) == 0


def test_couldnt_measure_beats_any_verdict():
    assert exit_code([("fail", "block")], ["DEEPGRAM_API_KEY is missing"]) == 2
    assert exit_code([("pass", "block")], ["the evaluation set changed since the baseline was recorded"]) == 2
