"""Storyboard modality registration and runner tests."""

from __future__ import annotations

from pathlib import Path
from types import SimpleNamespace

import pytest

from recoil.pipeline.core.dispatch import (
    PayloadValidationError,
    _reset_bootstrap_for_tests,
    dispatch,
    register_default_runners,
)
from recoil.pipeline.core.dispatch_context import DispatchContext
from recoil.pipeline.core.registry import RunResult, _reset_for_tests, is_registered
from recoil.pipeline.core.runners.storyboard_runner import StoryboardRunner


class _StepRunnerStub:
    def __init__(self) -> None:
        self.calls: list[dict] = []

    def execute_keyframe(self, **kwargs):
        self.calls.append(kwargs)
        return SimpleNamespace(
            shot_id=kwargs.get("shot_id", "EP001_CONT_004"),
            success=True,
            final_state="keyframe_generated",
            output_path="/tmp/storyboard.png",
            cost_usd=0.41,
            error=None,
            take_index=0,
            gate_verdict=None,
            model=kwargs.get("model", "gpt-image-2"),
            pipeline="still",
        )

    def execute_video(self, **kwargs):
        raise AssertionError("storyboard tests must not call execute_video")


@pytest.fixture(autouse=True)
def _reset_registry():
    _reset_for_tests()
    _reset_bootstrap_for_tests()
    yield
    _reset_for_tests()
    _reset_bootstrap_for_tests()


def test_storyboard_modality_registered():
    stub = _StepRunnerStub()

    register_default_runners(stub)
    register_default_runners(stub)

    assert is_registered("storyboard")


def test_storyboard_payload_contract():
    stub = _StepRunnerStub()
    context = DispatchContext(
        caller_id="test",
        step_runner=stub,
        receipts_log_path="DISABLED",
    )

    with pytest.raises(PayloadValidationError) as exc:
        dispatch(
            "storyboard",
            {
                "shot_id": "EP001_CONT_004",
                "prompt": "draw the strip",
                "model": "gpt-image-2",
                "size_override": "1728x1536",
                "filename_stem": "EP001_CONT_004_v01",
            },
            context=context,
        )

    assert "save_dir" in str(exc.value)


def test_storyboard_runner_translates_payload(tmp_path):
    stub = _StepRunnerStub()
    runner = StoryboardRunner(stub)
    sidecar_extra = {"kind": "storyboard", "batch_id": "EP001_CONT_004"}

    result = runner.run(
        {
            "shot_id": "EP001_CONT_004",
            "prompt": "draw the strip",
            "model": "gpt-image-2",
            "reference_images": ["/tmp/ref.png"],
            "quality": "high",
            "size_override": "1728x1536",
            "aspect_ratio": "1:1",
            "inputs_snapshot": {"source": "test"},
            "save_dir": str(tmp_path / "storyboards"),
            "filename_stem": "EP001_CONT_004_v01",
            "sidecar_extra": sidecar_extra,
        }
    )

    assert isinstance(result, RunResult)
    assert result.success is True
    assert result.modality == "storyboard"
    assert result.output_path == "/tmp/storyboard.png"

    call = stub.calls[0]
    assert call["save_dir"] == tmp_path / "storyboards"
    assert isinstance(call["save_dir"], Path)
    assert call["filename_stem"] == "EP001_CONT_004_v01"
    assert call["sidecar_extra"] is sidecar_extra
    assert call["size_override"] == "1728x1536"
