"""
Practice: two shortcuts around an expensive model call, the way Lab 12's scripts 05 and 06 do them.
A semantic cache reuses a saved answer when a new question scores similar enough to a saved one.
A cascade lets a cheap model answer first and sends the request to a bigger model when the cheap
one is unsure. You'll write the similarity score, the cache's decision, the cheap model's
confidence, what a cascade costs and gets right, and how the lab chooses the cascade's cutoff.

Fill in the TODOs, then run the tests:
    pytest test_shortcuts_practice.py        (locally)
or press "Run tests" on the chapter page.
"""
import math


def cosine(a: list[float], b: list[float]) -> float:
    """Cosine similarity of two embeddings: their dot product divided by both lengths.
    1 means the same direction (the same spot on the map of meaning); 0 means unrelated."""
    # TODO
    raise NotImplementedError


def cache_reuses(ok: list[bool], sims: list[float], cutoff: float) -> dict:
    """ok[i]: is the saved answer right for pair i's new question? sims[i]: the pair's similarity.
    The cache reuses the saved answer when the similarity is at or above the cutoff.
    Return {"good": reuses that were right, "wrong": reuses that sent a wrong answer}."""
    # TODO
    raise NotImplementedError


def confidence(logprob: float) -> float:
    """The API returns a logprob (the natural log of the probability the model gave its answer).
    Turn it into a plain probability, 0 to 1."""
    # TODO
    raise NotImplementedError


def cascade(tickets: list[dict], cutoff: float) -> dict:
    """Each ticket: {"priority": the right answer, "small": {"answer", "confidence", "cost"},
    "big": {"answer", "cost"}}. The small model answers every ticket. When its confidence is below
    the cutoff, the big model answers instead, and you pay for BOTH calls.
    Return {"right": answers that match the priority, "sent_up": tickets sent to the big model,
    "cost": the total cost}."""
    # TODO
    raise NotImplementedError


def choose_cutoff(dev: list[dict], candidates: list[float]) -> float:
    """Script 06's rule: the lowest candidate whose cascade gets at least as many dev tickets right
    as the big model alone. (Lower cutoff = fewer tickets sent up = cheaper.)"""
    # TODO
    raise NotImplementedError
