"""Tests from Lab 04. Run: pytest test_stats_practice.py"""
import math
import random

from stats_practice import bootstrap_ci, corpus_wer, paired_bootstrap, verdict


def make_clips(n, seed=1):
    """n clips, each 4-55 words, from speakers of very different difficulty (like real data)."""
    r = random.Random(seed)
    words, errors = [], []
    for _ in range(n):
        w = r.randint(4, 55)
        rate = r.choice([0.0, 0.02, 0.04, 0.04, 0.06, 0.15])
        words.append(w)
        errors.append(sum(r.random() < rate for _ in range(w)))
    return errors, words


def test_corpus_wer():
    assert math.isclose(corpus_wer([1, 1], [2, 40]), 2 / 42)


def test_interval_contains_the_estimate():
    errors, words = make_clips(300)
    lo, hi = bootstrap_ci(errors, words)
    assert lo < corpus_wer(errors, words) < hi


def test_more_clips_narrow_the_interval():
    # Lab 04: ±3.65 points at 25 clips, ±0.97 at 300
    errors, words = make_clips(300)
    lo25, hi25 = bootstrap_ci(errors[:25], words[:25])
    lo300, hi300 = bootstrap_ci(errors, words)
    assert (hi300 - lo300) < (hi25 - lo25) / 2


def test_bootstrap_is_reproducible():
    errors, words = make_clips(100)
    assert bootstrap_ci(errors, words, seed=3) == bootstrap_ci(errors, words, seed=3)


def test_a_clear_improvement_is_detected():
    errors_a, words = make_clips(300)
    errors_b = [e // 2 for e in errors_a]          # B halves every clip's errors
    lo, hi = paired_bootstrap(errors_a, errors_b, words)
    assert hi < 0 and verdict(lo, hi) == "better"


def test_a_tiny_change_cant_be_told_apart():
    errors_a, words = make_clips(300)
    r = random.Random(9)
    errors_b = list(errors_a)
    for i in r.sample(range(300), 20):             # ~15% of clips change a little, both ways
        errors_b[i] = max(0, errors_b[i] + r.choice([-1, 1]))
    lo, hi = paired_bootstrap(errors_a, errors_b, words)
    assert lo < 0 < hi and verdict(lo, hi) == "can't tell"


def test_pairing_is_narrower_than_separate_intervals():
    errors_a, words = make_clips(300)
    errors_b = [max(0, e - 1) if i % 3 == 0 else e for i, e in enumerate(errors_a)]
    lo, hi = paired_bootstrap(errors_a, errors_b, words)
    la, ha = bootstrap_ci(errors_a, words)
    assert (hi - lo) < (ha - la)


def test_verdict():
    assert verdict(-3.74, -2.05) == "better"
    assert verdict(-0.57, 0.45) == "can't tell"
    assert verdict(0.2, 1.1) == "worse"
