"""REC-130: a standalone/probe dispatch whose shot_id has no EP_SH grammar
(e.g. "SEEDANCE_I2V_<ts>") must save its (paid) output under a sanitized
fallback filename instead of crashing post-generation in the strict episode
namer (build_filename raises "no SH<num> token"). Real episode shot_ids still
use the strict grammar.
"""
from types import SimpleNamespace
from unittest.mock import MagicMock

from recoil.execution.step_runner import StepRunner
from recoil.execution.step_types import ProjectPaths


def _runner(tmp_path):
    paths = ProjectPaths(
        project="_probes", project_root=tmp_path,
        frames_dir=tmp_path / "frames", video_dir=tmp_path / "video",
        plans_dir=tmp_path / "plans", previs_dir=tmp_path / "previs",
    )
    for d in (paths.frames_dir, paths.video_dir, paths.plans_dir, paths.previs_dir):
        d.mkdir()
    store = MagicMock()
    store.get_shot.return_value = None
    return StepRunner(store=store, paths=paths)


def _result():
    return SimpleNamespace(video_data=b"\x00\x00fake-mp4-bytes", video_url=None)


def test_non_conformant_probe_shot_id_saves_sanitized_filename(tmp_path):
    runner = _runner(tmp_path)
    # Before REC-130 this raised ValueError("... has no SH<num> token; cannot
    # build filename") AFTER the paid render — losing the output.
    out = runner._save_video(
        "SEEDANCE_I2V_1782234253", _result(), take_number=1, model="kling-o3-pro"
    )
    assert out.exists()
    assert out.name == "SEEDANCE_I2V_1782234253_take1.mp4"


def test_conformant_shot_id_still_uses_strict_grammar(tmp_path):
    runner = _runner(tmp_path)
    out = runner._save_video(
        "EP001_SH03", _result(), take_number=2, model="kling-o3-pro"
    )
    # Strict episode grammar unchanged for real shots (build_filename SHORT grammar).
    assert out.name == "EP001_SH3_take2.mp4"
