"""Phase 7 (L + N + O) — sidecar provenance threading tests.

Asserts that the sidecar provenance keys added in Phase 6 stay populated
with the upstream-threaded values from Phase 7:

  Bug L: seed captured from the fal response into RunResult.metadata.seed
  Bug N: gate_results threaded through the unified payload into the sidecar.
  Bug O: prompt_engine_version is a 12-char hex hash, not a dotted module path.
         prompt_layers, when supplied via the payload, lands in provenance.

These tests use the `_write_sidecar` helper directly (mirroring the
Phase 6 test pattern in test_step_runner.py) — pragmatism over a full
StepRunner integration mock.
"""

from __future__ import annotations

import json
import re
from types import SimpleNamespace

from recoil.execution import step_runner as step_runner_mod


def _make_bare_step_runner():
    """Build a StepRunner instance bypassing __init__ — sidecar helper is pure."""
    return step_runner_mod.StepRunner.__new__(step_runner_mod.StepRunner)


def _make_run_result_stub(*, cost_usd: float = 1.23, metadata=None):
    """Build a RunResult-shaped stub with cost_usd and metadata."""
    return SimpleNamespace(cost_usd=cost_usd, metadata=metadata or {})


def test_seed_populated_when_provider_returns(tmp_path):
    """When the fal-derived RunResult metadata contains a seed, the sidecar
    provenance.seed equals that integer."""
    sr = _make_bare_step_runner()
    video_path = tmp_path / "seedy.mp4"
    video_path.write_bytes(b"")

    rr = _make_run_result_stub(metadata={"seed": 2010003547, "request_id": "abc-123"})
    sr._write_sidecar(
        video_path=video_path,
        run_result=rr,
        unified_payload={
            "prompt": "p",
            "model": "seeddance-2.0",
            "modality": "i2v",
        },
    )
    data = json.loads(video_path.with_suffix(".mp4.json").read_text())
    assert data["provenance"]["seed"] == 2010003547


def test_gate_results_populated_when_gate_ran(tmp_path):
    """``gate_results`` passed to _write_sidecar flows to provenance.gate_results."""
    sr = _make_bare_step_runner()
    video_path = tmp_path / "gated.mp4"
    video_path.write_bytes(b"")

    gate_results = {
        "start_frame_gate": {"passed": True, "score": 0.94},
        "identity_gate": {"passed": True, "score": 0.88},
    }
    sr._write_sidecar(
        video_path=video_path,
        run_result=_make_run_result_stub(metadata={"seed": 1}),
        unified_payload={
            "prompt": "p",
            "model": "seeddance-2.0",
            "modality": "i2v",
        },
        gate_results=gate_results,
    )
    data = json.loads(video_path.with_suffix(".mp4.json").read_text())
    assert data["provenance"]["gate_results"] == gate_results


def test_prompt_engine_version_is_hash():
    """PROMPT_ENGINE_SCHEMA_VERSION is a 12-char lowercase hex hash."""
    from recoil.pipeline._lib.prompt_engine import PROMPT_ENGINE_SCHEMA_VERSION

    assert re.fullmatch(r"[a-f0-9]{12}", PROMPT_ENGINE_SCHEMA_VERSION), (
        f"PROMPT_ENGINE_SCHEMA_VERSION must be 12 lowercase hex chars, "
        f"got {PROMPT_ENGINE_SCHEMA_VERSION!r}"
    )


def test_prompt_engine_version_stamped_into_sidecar(tmp_path):
    """provenance.prompt_engine_version exactly equals the module constant."""
    from recoil.pipeline._lib.prompt_engine import PROMPT_ENGINE_SCHEMA_VERSION

    sr = _make_bare_step_runner()
    video_path = tmp_path / "stamped.mp4"
    video_path.write_bytes(b"")

    sr._write_sidecar(
        video_path=video_path,
        run_result=_make_run_result_stub(metadata={"seed": 7}),
        unified_payload={
            "prompt": "p",
            "model": "seeddance-2.0",
            "modality": "i2v",
        },
    )
    data = json.loads(video_path.with_suffix(".mp4.json").read_text())
    assert data["provenance"]["prompt_engine_version"] == PROMPT_ENGINE_SCHEMA_VERSION
    # And not a dotted module path (the Bug O original symptom).
    assert "." not in data["provenance"]["prompt_engine_version"]


def test_prompt_layers_populated(tmp_path):
    """``prompt_layers`` passed to _write_sidecar flows to provenance.prompt_layers."""
    sr = _make_bare_step_runner()
    video_path = tmp_path / "layered.mp4"
    video_path.write_bytes(b"")

    prompt_layers = {
        "scene": "wide shot of jade entering the corridor",
        "pose": "back to camera, walking forward",
        "identity": "JADE — wardrobe phase WW",
    }
    sr._write_sidecar(
        video_path=video_path,
        run_result=_make_run_result_stub(metadata={"seed": 1}),
        unified_payload={
            "prompt": "p",
            "model": "seeddance-2.0",
            "modality": "i2v",
        },
        prompt_layers=prompt_layers,
    )
    data = json.loads(video_path.with_suffix(".mp4.json").read_text())
    assert data["provenance"]["prompt_layers"] == prompt_layers


def test_phase6_keys_remain_intact(tmp_path):
    """Phase 6's provenance keys (refs_used, seed, gate_results, prompt_layers)
    must all remain present after Phase 7's edit. Regression guard against
    accidental dict-literal rewrites."""
    sr = _make_bare_step_runner()
    video_path = tmp_path / "all_keys.mp4"
    video_path.write_bytes(b"")

    sr._write_sidecar(
        video_path=video_path,
        run_result=_make_run_result_stub(metadata={"seed": 99}),
        unified_payload={
            "prompt": "p",
            "model": "seeddance-2.0",
            "modality": "r2v_multi",
            "reference_images": ["/refs/a.png"],
        },
        gate_results={"x": {"passed": True}},
        prompt_layers={"identity": "X"},
    )
    data = json.loads(video_path.with_suffix(".mp4.json").read_text())
    prov = data["provenance"]
    # Phase 6 keys.
    assert "refs_used" in prov
    assert "seed" in prov
    assert "gate_results" in prov
    assert "prompt_layers" in prov
    # Phase 7 key.
    assert "prompt_engine_version" in prov
