"""Tests on the replies recorded for the vision-docs video: Lab 08's own documents, questions and instruction
(02_documents_as_images.py), gpt-5.4-nano and gpt-5.4-mini, 3 runs each. Run: pytest test_pages_practice.py"""
from pages_practice import cost_per_1000, is_right, lowest_good_dpi, outcome, pair_in_order, short_columns, split_columns

# The price list's extracted text, exactly as PyMuPDF returned it. On the page, the Office chair's stock cell is
# blank and the Monitor arm has 45 in stock.
PRICE_LIST_TEXT = """Spring 2026 price list
Prices in USD. Stock as of April 1.
A blank stock cell means the item is on back order.
SKU
SKU-1043
SKU-1187
SKU-1202
SKU-1279
SKU-1310
SKU-1356
SKU-1401
SKU-1448
Product
Desk lamp
Office chair
Whiteboard
Filing cabinet
Paper shredder
Desk organizer
Monitor arm
Footrest
Price
24.90
189.00
64.50
142.00
98.00
15.75
72.30
29.99
In stock
140
33
7
21
260
45
18"""
HEADERS = ["SKU", "Product", "Price", "In stock"]

# (recorded reply, right answer, kind, setup) for a few of the 60 × 3 replies
REPLIES = [
    ("$4,317.30", 4317.3, "number", "nano, page image"),
    ("4317.30", 4317.3, "number", "nano, extracted text"),
    ("No", "No", "word", "nano, page image"),
    ("Yes", "No", "word", "nano, extracted text"),
    ("Email", "Phone", "text", "nano, extracted text"),
    ("room 4.12 on June 2 at 10.30", "4.12", "text", "nano, 75 DPI scan"),
    ("Figure 1: defect rate by month (% of units shipped).", "defect rate by month", "text", "nano, extracted text"),
    ("1.9%", 1.9, "number", "nano, page image"),
    ("18", 45, "number", "nano, extracted text"),
    ("Marcus Oyevaran", "Marcus Oyelaran", "text", "nano, page image"),
    ("June 18", "July 18", "text", "nano, page image"),
    ("NOT FOUND", 48500, "number", "nano, extracted text"),
    ("$849,500", 48500, "number", "nano, 50 DPI scan"),
]
EXPECTED = [True, True, True, False, False, True, True, True, False, False, False, False, False]


def test_is_right_grades_recorded_replies():
    got = [is_right(a, c, k) for a, c, k, _ in REPLIES]
    for (a, c, _, setup), g, want in zip(REPLIES, got, EXPECTED):
        assert g == want, f"{setup}: {a!r} for {c!r} should be {'right' if want else 'wrong'}"
    assert is_right("No.", "No", "word") and not is_right("Not sure", "No", "word")


def test_outcome_separates_safe_and_dangerous_failures():
    # nano on the extracted text: 20 questions x 3 runs, as (reply, right) counts from the recording
    text_runs = ([("INV-20417", True)] * 24 + [("NOT FOUND", False)] * 27 +
                 [("Yes", False)] * 3 + [("Email", False)] * 3 + [("18", False)] * 3)
    counts = {}
    for answer, right in text_runs:
        o = outcome(answer, right)
        counts[o] = counts.get(o, 0) + 1
    assert counts == {"right": 24, "not found": 27, "wrong": 9}
    assert outcome("Not found in the document.", False) == "not found"


def test_split_columns_reads_the_column_order():
    cols = split_columns(PRICE_LIST_TEXT, HEADERS)
    assert list(cols) == HEADERS
    assert len(cols["Product"]) == 8 and cols["Product"][6] == "Monitor arm"
    assert cols["In stock"] == ["140", "33", "7", "21", "260", "45", "18"]


def test_pairing_in_order_gives_the_footrests_number():
    pairs = pair_in_order(split_columns(PRICE_LIST_TEXT, HEADERS), "Product", "In stock")
    assert pairs["Monitor arm"] == "18"   # the page says 45; nano said 18 in all 3 runs
    assert pairs["Office chair"] == "33"  # the page says blank (back order); 33 is the Whiteboard's
    assert pairs["Footrest"] is None
    assert pairs["Desk lamp"] == "140"    # rows above the blank cell are fine


def test_short_columns_flags_the_blank_cell():
    cols = split_columns(PRICE_LIST_TEXT, HEADERS)
    assert short_columns(cols) == ["In stock"]
    assert short_columns({"a": ["1", "2"], "b": ["3", "4"]}) == []


def test_cost_per_1000_questions():
    # totals over the 60 recorded replies per setup; the lab's list prices (USD per 1M tokens)
    text = cost_per_1000(6510, 360, 60, 0.20, 1.25)
    image = cost_per_1000(71217, 394, 60, 0.20, 1.25)
    mini = cost_per_1000(71217, 360, 60, 0.75, 4.50)
    assert (round(text, 2), round(image, 2), round(mini, 2)) == (0.03, 0.25, 0.92)
    assert round(71217 / 6510) == 11  # about 11x the input tokens with the page image


def test_lowest_good_dpi():
    # the two scans at four resolutions: right of 6 questions x 3 runs (nano)
    results = {50: (4, 18), 75: (14, 18), 100: (14, 18), 150: (17, 18)}
    assert lowest_good_dpi(results, 0.9) == 150
    assert lowest_good_dpi(results, 0.75) == 75
    assert lowest_good_dpi(results, 1.0) is None
    assert lowest_good_dpi({150: (17, 18), 50: (4, 18)}, 0.2) == 50  # don't trust dict order
