"""
Practice: the pieces of Lab 08's monitoring (signals.py, detectors.py, canary.py).

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


def request_signals(text: str, declared_seconds: float, decoded_seconds: float) -> dict:
    """Signals you can compute on every request, without a reference transcript.

    Return {"empty": ..., "words_per_second": ..., "duration_mismatch": ...}:
      - empty:             the transcript has no words
      - words_per_second:  words / declared_seconds (floor declared_seconds at 0.1)
      - duration_mismatch: decoded / declared is more than 5% away from 1
        (it never happens normally, so one occurrence is news)

    TODO 1
    """
    return {"empty": False, "words_per_second": 0.0, "duration_mismatch": False}


def window_z(value: float, n: int, mean: float, sd: float) -> float:
    """How many standard errors one window's value is from normal, GIVEN how many requests it had.

    `mean` and `sd` are per request, from a reference period of normal traffic. The standard
    error of a window with n requests is sd / sqrt(n). A window with no requests scores 0.

    TODO 2
    """
    return 0.0


def cusum(zs: list[float], h: float, k: float = 0.5, cooldown: int = 12) -> list[int]:
    """Add up evidence: S = max(0, S + z - k), alert when S > h.

    Return the window indices where it alerts. After an alert, reset S to 0 and stay quiet for
    `cooldown` windows (an hour of 5-minute windows), so one incident counts once: an index t
    can only alert if t > previous alert + cooldown. S keeps accumulating during the cooldown.

    TODO 3
    """
    return []


def canary_alerts(rnd: dict, golden: dict, previous: dict | None = None, wer_margin: float = 2.0) -> list[str]:
    """The canary's alert rules. `rnd` and `previous` are rounds:
        {"changed": int, "errors": int, "must_pass_failures": int, "wer": float}
    `golden` is the accepted deploy's round: {"wer": float}.

    Return a list containing, in this order, whichever apply:
      - "transcripts changed"  if any clip's transcript differs from the golden one
      - "requests failed"      if any request failed
      - "must-pass"            if any must-pass phrase failed
      - "wer"                  if WER > golden WER + wer_margin in this round AND in the previous
                               one (if there is one), so one network blip doesn't page anyone

    TODO 4
    """
    return []
