"""
Practice: training without labels, measured. Lab 11's checks on a student copying its teacher
(05_distillation.py), the DPO loss (train.dpo_loss), and pass@k for rejection-sampling RFT (07_rft.py).

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

FIELDS = ["intent", "order_id", "sku", "urgency"]


def same_answer(a: dict, b: dict) -> bool:
    """True if two answers agree on all four fields. Compare as lowercased strings, so None == None
    and "TENT-4P" == "tent-4p".

    TODO 1
    """
    return False


def copied_mistakes(teacher: list[dict], student: list[dict], truth: list[dict]) -> tuple[int, int]:
    """For the emails where the teacher's answer is wrong (not the same as the truth), count how often the
    student gave exactly the teacher's answer. Return (teacher_wrong, copied).

    TODO 2
    """
    return (0, 0)


def dpo_loss(pol_c: float, pol_r: float, ref_c: float, ref_r: float, beta: float) -> float:
    """DPO loss for one preference pair, from sequence log-probabilities.
      pol_c, pol_r: the model being trained, on the chosen (better) and rejected (worse) answer
      ref_c, ref_r: the frozen starting model, on the same two answers
      margin = beta * ((pol_c - ref_c) - (pol_r - ref_r))
      loss   = -log(sigmoid(margin))

    TODO 3
    """
    return 0.0


def coverage(graded: dict[str, list[bool]]) -> dict:
    """graded maps each email to the grader's ticks (True) and crosses (False) for its tries, in order.
    Return {"pass1": share of emails whose FIRST try passed,
            "passk": share of emails with at least one passing try,
            "never": number of emails with no passing try,
            "kept":  {email: index of its first passing try}, only for emails with one}.
    "kept" is what rejection sampling trains on: one passing try per email, the first.

    TODO 4
    """
    return {"pass1": 0.0, "passk": 0.0, "never": 0, "kept": {}}
