"""The export builds the boat-cam tiles (`export_v3_instance.export_media_map`).

`docs/replay-production.md` said the tiles were missing because a workstation's user login cannot sign
v4 URLs. True, and second: `build_feed` returns `{meta, course, teams, frames}` and the exporter never
called `media_from_store` at all, so no exported feed has EVER carried a `media` key — verified by
grepping the four in the tree. With `feed.media = {}` the renderer's `mediaAt()` returns null and
`app.js` collapses every inset. Fixing only the credential would have changed nothing at all.

No credential here: the signer is faked, which is the point — the shape of the map and the behaviour
when signing fails are what this pins, and both are testable offline.
"""
import sys
from pathlib import Path

_HERE = Path(__file__).resolve().parent
sys.path.insert(0, str(_HERE.parents[1] / "export"))
sys.path.insert(0, str(_HERE.parents[3] / "ingest"))
sys.path.insert(0, str(_HERE.parents[2] / "live"))

import export_v3_instance as EXP  # noqa: E402
from store import InMemoryStore, VideoSegment  # noqa: E402

T0, T1 = 1_000_000, 1_600_000
BOAT = "u1:boat:1"
SLOT = f"{BOAT}:Mast"


def _store(*starts: int) -> InMemoryStore:
    s = InMemoryStore()
    s.upsert_slot(SLOT, None)
    for i, t in enumerate(starts):
        s.add_video_segment(VideoSegment(
            slot=SLOT, start_ms=t, end_ms=t + 2000, source="clip", rendition="front",
            gcs_path=f"gs://bucket/v3/media/u1/boat/1/Mast/clip{i}.mp4"))
    return s


def _signed(monkeypatch, fn) -> None:
    """Stand in for `read_server._signed_clip_url`, which needs GCS and a signing key."""
    import read_server
    monkeypatch.setattr(read_server, "_signed_clip_url", fn)


def test_the_clips_of_the_race_become_tiles(monkeypatch):
    _signed(monkeypatch, lambda path, minutes=30: f"https://signed/{path.rsplit('/', 1)[-1]}")
    store = _store(T0 + 10_000, T0 + 20_000)
    media = EXP.export_media_map(store, [BOAT], t0_ms=T0, t1_ms=T1)
    assert BOAT in media, "the boat must have a tile timeline"
    rows = media[BOAT]
    assert [r["tSec"] for r in rows] == [10.0, 20.0], "race-relative seconds, from trackStart"
    assert all(r["file"].startswith("https://signed/") for r in rows)
    assert all(r["video"] for r in rows)


def test_the_signature_lasts_days_not_the_live_plane_s_minutes():
    """A render takes 1.5-2 h and the recorder retries for longer after a GPU crash, so the read
    plane's 30-minute default would expire mid-capture — and `app.js` holds the last picture on a
    fetch error, so the tiles would go dark silently, partway through the film."""
    assert EXP.CLIP_URL_MINUTES >= 2 * 24 * 60, "hours of rendering need days of URL"
    assert EXP.CLIP_URL_MINUTES <= 7 * 24 * 60, "…and v4 signing caps at seven days"


def test_the_asked_for_lifetime_reaches_the_signer(monkeypatch):
    seen = []
    _signed(monkeypatch, lambda path, minutes=30: seen.append(minutes) or "https://x/y.mp4")
    EXP.export_media_map(_store(T0 + 5_000), [BOAT], t0_ms=T0, t1_ms=T1, clip_minutes=4321)
    assert seen == [4321]


def test_a_workstation_that_cannot_sign_gets_no_tiles_rather_than_no_export(monkeypatch, capsys):
    """The credential case, which is the state of this machine today. An export must still produce a
    renderable feed — the 3D picture and the commentary do not need a signature."""
    def _raise(path, minutes=30):
        raise RuntimeError("you need a private key to sign credentials")
    _signed(monkeypatch, _raise)
    media = EXP.export_media_map(_store(T0 + 5_000, T0 + 7_000), [BOAT], t0_ms=T0, t1_ms=T1)
    assert media == {}, "no signature ⇒ no tiles, and no crash"
    said = capsys.readouterr().out
    assert "could not be signed" in said, (
        "and it must SAY so — absent tiles otherwise look like a race that had no cameras")


def test_clips_outside_the_race_window_are_not_tiles(monkeypatch):
    """A buoy or a boat keeps filming across every race run on the course; a replay of one race must
    not pick up the next one's footage."""
    _signed(monkeypatch, lambda path, minutes=30: f"https://signed/{path.rsplit('/', 1)[-1]}")
    store = _store(T0 + 10_000, T1 + 60_000)          # the second is a later race
    rows = EXP.export_media_map(store, [BOAT], t0_ms=T0, t1_ms=T1)[BOAT]
    assert [r["tSec"] for r in rows] == [10.0]


def test_a_race_with_no_footage_adds_no_media_key(monkeypatch):
    _signed(monkeypatch, lambda path, minutes=30: "https://signed/x.mp4")
    assert EXP.export_media_map(InMemoryStore(), [BOAT], t0_ms=T0, t1_ms=T1) == {}
