"""DispatchContext tests."""
import sys
import pathlib
sys.path.insert(0, str(pathlib.Path(__file__).resolve().parent.parent.parent.parent))
from recoil.core.paths import ensure_pipeline_importable  # noqa: E402
ensure_pipeline_importable()

import pytest  # noqa: E402
from recoil.pipeline.core.dispatch_context import DispatchContext  # noqa: E402


class _StubStepRunner:
    def execute_keyframe(self, **kw): return None
    def execute_video(self, **kw): return None


def test_construct_minimal():
    sr = _StubStepRunner()
    ctx = DispatchContext(caller_id="test", step_runner=sr)
    assert ctx.caller_id == "test"
    assert ctx.project is None
    assert ctx.episode is None
    assert ctx.receipts_log_path is None
    assert ctx.provenance_overrides == {}


def test_construct_full():
    sr = _StubStepRunner()
    ctx = DispatchContext(
        caller_id="production_loop",
        step_runner=sr,
        project="tartarus",
        episode=1,
        receipts_log_path="/tmp/r.jsonl",
        provenance_overrides={"k": "v"},
    )
    assert ctx.project == "tartarus"
    assert ctx.episode == 1
    assert ctx.provenance_overrides == {"k": "v"}


def test_rejects_empty_caller_id():
    with pytest.raises(ValueError):
        DispatchContext(caller_id="", step_runner=_StubStepRunner())


def test_rejects_none_step_runner():
    with pytest.raises(ValueError):
        DispatchContext(caller_id="test", step_runner=None)


def test_frozen():
    ctx = DispatchContext(caller_id="test", step_runner=_StubStepRunner())
    with pytest.raises(Exception):
        ctx.caller_id = "tampered"  # type: ignore
