"""Tests for the execute_keyframe no-fix-available infinite loop fix."""
import pytest
from unittest.mock import MagicMock, patch
from pathlib import Path


def test_no_fix_available_terminates_immediately(tmp_path):
    """When feedback agent returns None, execute_keyframe must NOT retry the same broken prompt."""
    from recoil.execution.step_runner import StepRunner
    from recoil.execution.step_types import ProjectPaths, GateVerdict
    from recoil.execution.feedback import FeedbackAgent

    store = MagicMock()
    store.get_shot.return_value = {"status": "keyframe_generating"}
    paths = ProjectPaths(
        project="test", 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()

    runner = StepRunner(store=store, paths=paths)

    fail_verdict = GateVerdict(
        passed=False, gate_name="gate_2a",
        reason="identity drift", details={}, cost=0.0, retriable=True,
    )
    fake_gate = MagicMock(return_value=fail_verdict)
    # CP-2 Phase 6: execute_keyframe now dispatches via resolve_adapter +
    # adapter.direct_submit_image instead of get_client(...).generate_keyframe.
    fake_adapter = MagicMock()
    fake_adapter.direct_submit_image.return_value = {
        "image_bytes": b"fake", "native_id": "test-id", "operation": None,
    }

    with patch(
        "recoil.execution.providers.resolve_adapter",
        return_value=(fake_adapter, "default"),
    ), patch.object(FeedbackAgent, "diagnose", return_value=None) as mock_diagnose:
        result = runner.execute_keyframe(
            shot_id="EP001_SH01",
            prompt="A character",
            model="gemini-3-pro-image-preview",
            gates=[fake_gate],
            max_gate_retries=4,
        )

    # diagnose called exactly ONCE — once it returns None, we escalate, not retry
    assert mock_diagnose.call_count == 1
    # Total generate_keyframe calls: 1 (initial) — does NOT retry after no-fix
    assert fake_adapter.direct_submit_image.call_count == 1
    assert result.success is False
    assert result.final_state == "icu_escalated"
