"""The watcher over the one thing that cannot be reconstructed afterwards.

`recording_anchor` is the only record of where UTC zero sits in OBS's recording, so a day recorded
without it can be watched but not cut. What makes watching it awkward is that "nothing written" is its
NORMAL state — it writes only while OBS records, and OBS is closed most of the week. A watchdog that
treated silence as failure would restart it all weekend; one that treated silence as health would miss
the only failure that matters.
"""
from __future__ import annotations

import sys
from pathlib import Path

import pytest

_LIVE = Path(__file__).resolve().parents[2] / "live"
if str(_LIVE) not in sys.path:
    sys.path.insert(0, str(_LIVE))

from anchor_watchdog import IDLE, OK, STALE, UNKNOWN, verdict  # noqa: E402

NOW = 1_787_500_000_000


def samples(*ages_s):
    return [{"tUtcMs": NOW - int(a * 1000), "anchorUtcMs": NOW, "path": "D:/rec/a.mp4"} for a in ages_s]


def test_recording_and_current_is_ok():
    state, _ = verdict(samples(20), now_ms=NOW, obs_recording=True)
    assert state == OK


def test_recording_but_not_written_for_minutes_is_the_failure_worth_restarting_for():
    """The one case that costs something: OBS is filling a file and nothing is writing down where its
    frame zero is. Every minute in that state is a minute of the day that cannot be cut afterwards."""
    state, why = verdict(samples(600), now_ms=NOW, obs_recording=True)
    assert state == STALE
    assert "600s" in why


def test_recording_with_no_samples_at_all_is_stale_not_unknown():
    """A sampler that has never written while OBS records is the same failure as one that stopped —
    and it is the shape a never-started process takes, which is exactly what happened on the render
    box, where the sampler could not even import until 2026-08-24."""
    assert verdict([], now_ms=NOW, obs_recording=True)[0] == STALE


def test_obs_not_recording_is_idle_however_old_the_log_is():
    """Its normal state. A watchdog that restarted on this would spend the week restarting a process
    that is behaving perfectly, and would be ignored by the time it mattered."""
    for age in (10, 6_000, 600_000):
        assert verdict(samples(age), now_ms=NOW, obs_recording=False)[0] == IDLE
    assert verdict([], now_ms=NOW, obs_recording=False)[0] == IDLE


def test_obs_unreachable_is_unknown_and_never_ok():
    """The house rule, and here it has teeth beyond reporting: `unknown` must not restart anything.
    If OBS is closed, restarting the sampler changes nothing and would crash-loop for the length of a
    lunch break."""
    state, why = verdict(samples(9_000), now_ms=NOW, obs_recording=None)
    assert state == UNKNOWN
    assert state != OK
    assert "could not be reached" in why


@pytest.mark.parametrize(("recording", "expected_exit"),
                         [(True, 1), (False, 0), (None, 0)])
def test_only_stale_is_actionable(recording, expected_exit, tmp_path, monkeypatch):
    """The caller restarts on exit 1. `idle` and `unknown` must exit 0, or an unreachable OBS becomes
    a restart loop."""
    import anchor_watchdog

    anchor = tmp_path / "recording_anchor.jsonl"
    anchor.write_text("", encoding="utf-8")                       # no samples: stale iff recording
    monkeypatch.setattr(anchor_watchdog, "obs_recording_now", lambda: recording)
    assert anchor_watchdog.main(["--anchor", str(anchor)]) == expected_exit


def test_a_missing_anchor_file_is_read_as_no_samples_not_a_crash(tmp_path, monkeypatch):
    """Before the first race of the day the file does not exist yet."""
    import anchor_watchdog

    monkeypatch.setattr(anchor_watchdog, "obs_recording_now", lambda: False)
    assert anchor_watchdog.main(["--anchor", str(tmp_path / "absent.jsonl")]) == 0
