"""Run locally with pytest test_eval_practice.py or on the chapter page."""

from eval_practice import CUSTOMER, OFF_TOPIC, precision_at_k, recall_at_k, rejected_off_topic, score_run


def test_original_cutoff_hides_right_articles():
    assert score_run(CUSTOMER, 0.50) == {
        "ranked_right": 7, "answered": 3, "correct_answer": 3, "handed_off": 5,
    }


def test_lower_cutoff_does_not_fix_wrong_rank():
    assert score_run(CUSTOMER, 0.15) == {
        "ranked_right": 7, "answered": 8, "correct_answer": 7, "handed_off": 0,
    }


def test_off_topic_rejection():
    assert rejected_off_topic(OFF_TOPIC, 0.15) == 2
    assert rejected_off_topic(OFF_TOPIC, 0.08) == 0


def test_gate_boundary_and_empty_run():
    assert score_run([(0.50, True), (0.49, False)], 0.50)["correct_answer"] == 1
    assert score_run([], 0.50) == {
        "ranked_right": 0, "answered": 0, "correct_answer": 0, "handed_off": 0,
    }


def test_precision_and_recall_at_3_from_the_lab():
    # Lab 03's own golden set (AI articles), top 3 results by article, paragraph chunks
    attention = ["transformers", "transformers", "fine_tuning"]
    assert round(precision_at_k(attention, {"transformers"}, 3), 3) == 0.667
    assert recall_at_k(attention, {"transformers"}, 3) == 1.0
    # "Why do large language models hallucinate?" is labelled with two articles; its top 3
    # contained ai_safety and never rag
    assert recall_at_k(["ai_safety"], {"ai_safety", "rag"}, 3) == 0.5
    # made-up example: three chunks of one right article score perfect precision,
    # while recall shows the second right article is missing
    same_article = ["ai_safety", "ai_safety", "ai_safety"]
    assert precision_at_k(same_article, {"ai_safety", "rag"}, 3) == 1.0
    assert recall_at_k(same_article, {"ai_safety", "rag"}, 3) == 0.5
