"""The start sequence is SPOKEN, not beeped.

The renderer used to sound tones: a short beep each of the last ten seconds, a long one on the gun,
a mark on each minute. A beep tells a viewer that something happened; it never tells them WHAT, and
someone joining mid-sequence learns nothing at all from it. The sequence now says every whole minute
by name and counts the last ten seconds down one bare number a second, like a launch count.

These tests hold the two properties that make that work: every second of the count is filled, and
each call lands on its own second rather than a beat late.
"""
import json
import sys
from pathlib import Path

from commentary_i18n import LANGS
from conftest import REAL_JSON
from score_race import enrich

sys.path.insert(0, str(Path(__file__).resolve().parent.parent.parent.parent / "scoring"))
from commentary_banks import COUNTDOWN_MIN, COUNTDOWN_TICK  # noqa: E402


def _countdowns(gun_sec: int = 180):
    """`{toGun: text}` for the countdown calls a real race produces, in English."""
    feed = json.loads(REAL_JSON.read_text(encoding="utf-8"))
    feed["meta"]["gunUtcMs"] = feed["meta"]["trackStartUtcMs"] + gun_sec * 1000
    out = enrich(feed)
    return {gun_sec - e["tSec"]: e["i18n"]["en"]
            for e in out["events"] if e.get("type") == "countdown"}


def test_every_one_of_the_last_ten_seconds_is_counted():
    """A launch count with a hole in it is not a count. Ten through one, each on its own second."""
    calls = _countdowns()
    for n in range(1, 11):
        assert n in calls, f"nothing spoken at T-{n}"
        assert calls[n] == COUNTDOWN_TICK["en"][n]


def test_each_whole_minute_of_the_sequence_is_named_except_the_one_it_opens_on():
    """Every minute the sequence counts DOWN through, so the bank never has to know how long the
    sequence is: a five-minute sequence says four, three, two, one.

    The opening call is deliberately absent. It is the one call that announces nothing — the start of
    the sequence is already unmistakable from the race clock appearing and the warning signal on the
    water — and it lands on the same instant as the welcome, so the viewer's first experience of the
    broadcast would be two voices at once.
    """
    calls = _countdowns(gun_sec=300)
    for minutes in (4, 3, 2, 1):
        assert calls.get(minutes * 60) == COUNTDOWN_MIN["en"][minutes], f"no {minutes}-minute call"
    assert 300 not in calls, "the sequence must not announce the minute it opens on"


def test_the_opening_call_is_suppressed_at_any_sequence_length():
    """The rule is about the sequence's OWN start, not about a particular number of minutes — so it
    holds for the four-minute sequence TRWC sails and the five-minute RRS 26 one alike."""
    for gun_sec in (180, 240, 300):
        calls = _countdowns(gun_sec=gun_sec)
        assert gun_sec not in calls, f"{gun_sec // 60}-minute sequence announced its own opening"
        # …and the next one down is still called, so suppressing the opening silenced nothing else.
        assert (gun_sec - 60) in calls, f"{gun_sec // 60}-minute sequence lost its second call too"


def test_a_call_lands_on_its_own_second_not_a_beat_late():
    """The old code deliberately spoke the minute call a second AFTER the mark, so the beep led and
    the voice confirmed. With the beep gone the voice IS the signal, and a signal that arrives late
    is the wrong signal — these are the instants the broadcast synchronises to."""
    calls = _countdowns()
    for mark in (120, 60):          # 180 is this sequence's opening call — deliberately absent
        assert mark in calls, f"the {mark // 60}-minute call is not on its mark"
    assert 59 not in calls and 119 not in calls, "no call one second past its mark"


def test_the_count_is_spoken_in_every_language():
    """A viewer picks the language with ?lang=; a countdown that only exists in English is a silent
    countdown for everyone else."""
    for lng in LANGS:
        assert set(COUNTDOWN_TICK[lng]) == set(range(1, 11))
        assert set(COUNTDOWN_MIN[lng]) == set(range(1, 11))
        assert all(COUNTDOWN_TICK[lng][n].strip() for n in range(1, 11))


def test_every_minute_call_names_what_the_time_is_for():
    """A bare minute count is ambiguous to someone who joins the stream mid-sequence."""
    for minutes in range(1, 11):
        assert "to start" in COUNTDOWN_MIN["en"][minutes].lower()
        assert "till start" in COUNTDOWN_MIN["sv"][minutes].lower()
