import json

from recoil.pipeline._lib.dispatch_payload import PayloadContext, build_unified_payload


def test_identity_gate_flag_stores_serializable_ref_paths_not_callable(tmp_path, monkeypatch):
    """RECOIL_IDENTITY_GATE=1 stores a SERIALIZABLE ref-path spec (strings), NOT the
    gate callable. A callable in the payload breaks save_scene (json.dumps) and the
    Workflow round-trip invariant; the runner builds the gate from this spec."""
    ref_path = tmp_path / "jade_ref.png"
    ref_path.write_bytes(b"ref")
    monkeypatch.setenv("RECOIL_IDENTITY_GATE", "1")

    payload = build_unified_payload(
        PayloadContext(
            project="tartarus",
            modality="video_i2v",
            shot_id="EP001_SH01",
            prompt="test prompt",
            reference_image_paths=[ref_path],
        )
    )

    assert payload["reference_images"] == [str(ref_path)]
    assert payload["identity_gate_ref_paths"] == [str(ref_path)]
    assert "gates" not in payload  # never a callable in the persisted payload
    # The whole payload must survive json.dumps — this is exactly what save_scene
    # does, and a callable here is what crashed the first live run.
    json.dumps(payload)


def test_identity_gate_flag_unset_keeps_payload_clean(tmp_path, monkeypatch):
    ref_path = tmp_path / "jade_ref.png"
    ref_path.write_bytes(b"ref")
    monkeypatch.delenv("RECOIL_IDENTITY_GATE", raising=False)

    payload = build_unified_payload(
        PayloadContext(
            project="tartarus",
            modality="video_i2v",
            shot_id="EP001_SH01",
            prompt="test prompt",
            reference_image_paths=[ref_path],
        )
    )

    assert "gates" not in payload
    assert "identity_gate_ref_paths" not in payload
    json.dumps(payload)
