"""Tests on the recorded runs behind Lab 08 Script 4 (multimodal RAG): the 24 questions' search ranks, real
gpt-5.4-nano answers and transcripts ("cards"), and the token totals over 3 runs. Run: pytest test_scan_practice.py"""
from scan_practice import cost_per_1000, found, is_right, names_on, unknown_names

# Where search put each question's right page: 8 invoices, then 8 scanned memos, then 8 dashboard screenshots.
FILE_TEXT = [1, 1, 1, 1, 1, 1, 1, 1, 22, 21, 20, 16, 18, 17, 23, 15, 14, 10, 12, 7, 10, 9, 17, 21]
CLIP = [4, 1, 1, 8, 3, 7, 6, 5, 16, 15, 12, 3, 12, 12, 12, 23, 7, 4, 5, 12, 4, 4, 5, 1]
CARDS = [  # written-out cards, runs 1-3
    [1] * 16 + [3] + [1] * 7,
    [1] * 16 + [3, 1, 1, 2] + [1] * 4,
    [1] * 24,
]

VENDORS = ["Northwind Supplies", "Contoso Office", "Fabrikam Parts", "Tailspin Freight",
           "Litware Labs", "Adatum Cleaning", "Proseware Print", "Wingtip Catering"]
PROJECTS = ["Heron", "Kestrel", "Osprey", "Plover", "Wren", "Ibis", "Merlin", "Tern"]
SERVICES = ["checkout", "search", "payments", "auth", "inventory", "shipping", "notifications", "reviews"]
KNOWN = {"invoice": VENDORS, "memo": PROJECTS, "dashboard": SERVICES}

# Real cards: a vision model's transcript of each page, written once when the page arrived.
TERN = "MEMO\n\nRe: Project Term\n\nProject Term is approved with a budget of $91,000.\n\nThe kickoff is in room 2.19.\n\nPlease send questions to the project office."
HERON = "MEMO\n\nRe: Project Heron\n\nProject Heron is approved with a budget of $86,000.\nThe kickoff is in room 4.3.\nPlease send questions to the project office."
IBIS = "MEMO.\n\nRe: Project IbIs\n\nProject IbIs is approved with a budget of $52,000.\n\nThe kickoff is in room 6:21.\n\nPlease send questions to the project office."
MOVER = "MEMO\n\nRe: Project Mover\n\nProject Mover is approved with a budget of $66,000.\n\nThe kickoff is in room 2.15\n\nPlease send questions to the project office."
ADATUM = "Datum Cleaning\n\nINVOICE  \nInvoice No: INV-18269\n\nItem | Qty | Unit price | Amount  \nService item 1 | 13 | 337.00 | 4,381.00  \nService item 2 | 13 | 75.00 | 975.00  \nService item 3 | 2 | 193.00 | 386.00  \n\nTotal due: $5,742.00"
NORTHWIND = "Northwind Supplies\n\nINVOICE  \nInvoice no: INV-39714\n\nItem | Qty | Unit price | Amount  \nService item 1 | 12 | 212.00 | 2,544.00  \nService item 2 | 5 | 118.00 | 590.00  \nService item 3 | 2 | 63.00 | 126.00  \n\nTotal due: $3,260.00"
CHECKOUT = "checkout-service.weekly dashboard\n\np95 latency: 233 ms  \nError rate: 1.1%  \nRequests: 3.8M  \n\nLine chart: latency over the days of the week (Mon, Tue, Wed, Thu, Fri, Sat, Sun). It shows p95 latency values across the week, with the lowest point on Tue, a peak on Wed (highest point), and lower values on Sat, then slightly rising/flat on Sun."


def test_found_reproduces_the_search_scores():
    # Cards from the file's text: only the 8 invoices have any text to search.
    assert found(FILE_TEXT, 3) == 8
    # CLIP, matching by picture: first for 3 of 24, in the top 3 for 5.
    assert (found(CLIP, 1), found(CLIP, 3)) == (3, 5)
    # Written-out cards: in the top 3 for 24 of 24 in every run; first for 23, 22, 24.
    assert [found(r, 3) for r in CARDS] == [24, 24, 24]
    assert [found(r, 1) for r in CARDS] == [23, 22, 24]


def test_is_right_matches_the_labs_scoring():
    assert is_right("$5,742.00", 5742.0)
    assert is_right("4062.00", 4062.0)
    assert is_right("91000", 91000.0)
    assert not is_right("NOT FOUND", 91000.0)  # Tern, from the cards, every run
    assert not is_right("83000", 66000.0)  # Plover from page images: Osprey's budget


def test_names_on_reads_each_kind_of_card():
    assert names_on(HERON, "memo") == ["Heron", "Heron"]
    assert names_on(CHECKOUT, "dashboard") == ["checkout"]
    assert names_on(NORTHWIND, "invoice") == ["Northwind Supplies"]


def test_unknown_names_flags_the_slips():
    # Tern was written "Term" in all 3 runs: search still found it, the answer said NOT FOUND.
    assert unknown_names(TERN, "memo", PROJECTS) == ["Term"]
    # Run 3 wrote "Datum Cleaning"; that answer said NOT FOUND too.
    assert unknown_names(ADATUM, "invoice", VENDORS) == ["Datum Cleaning"]
    # The lab's own earlier run wrote Plover as "Mover", and that memo dropped out of the top 3.
    assert unknown_names(MOVER, "memo", PROJECTS) == ["Mover"]
    # A harmless slip: the answer was still right, but a case-sensitive check flags it.
    assert unknown_names(IBIS, "memo", PROJECTS) == ["IbIs"]
    # Cards that are right aren't flagged.
    for card, kind in [(HERON, "memo"), (NORTHWIND, "invoice"), (CHECKOUT, "dashboard")]:
        assert unknown_names(card, kind, KNOWN[kind]) == []
    assert unknown_names("", "memo", PROJECTS) == ["(no name)"]


def test_cost_per_1000():
    # Total input and output tokens over 72 answers (24 questions x 3 runs).
    assert round(cost_per_1000(18963, 410, 72), 2) == 0.06  # from the cards
    assert round(cost_per_1000(189135, 397, 72), 2) == 0.53  # from the page images
    assert round(cost_per_1000(206565, 391, 72), 2) == 0.58  # pages + cards
    # Writing the cards: 24 pages per run, paid once when a page arrives.
    per_page = [cost_per_1000(i, o, 24) for i, o in [(21726, 1935), (21726, 1922), (21726, 1800)]]
    assert round(sum(per_page) / 3, 2) == 0.28
