"""GenerationReceipt tests."""

import sys
import pathlib
import json
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.registry import RunResult  # noqa: E402
from recoil.pipeline.core.receipts import GenerationReceipt, make_receipt_id, utc_now_iso8601  # noqa: E402


def _sample_run_result(success=True):
    return RunResult(
        id="X_image_t2i_1700000000",
        modality="image_t2i",
        output_path="/tmp/x.png",
        output_url=None,
        metadata={"cost_usd": 0.04, "final_state": "keyframe_generated", "model": "nbp"},
        success=success,
        error=None,
    )


def test_receipt_minimal_construction():
    rr = _sample_run_result()
    g = GenerationReceipt(
        receipt_id="rcpt_1_X_image_t2i",
        modality="image_t2i",
        caller_id="test",
        project="tartarus",
        episode=1,
        shot_id="X",
        timestamp_utc=utc_now_iso8601(),
        run_result=rr,
    )
    assert g.eval_scores == {}
    assert g.provenance == {}
    assert g.run_result is rr


def test_receipt_to_dict_then_json_serializable():
    rr = _sample_run_result()
    g = GenerationReceipt(
        receipt_id="rcpt_1_X_image_t2i",
        modality="image_t2i",
        caller_id="dispatch_cli",
        project="tartarus",
        episode=1,
        shot_id="X",
        timestamp_utc="2026-04-27T03:14:15Z",
        run_result=rr,
        provenance={"dispatch_path": "dispatch_cli", "model": "nbp"},
    )
    d = g.to_dict()
    s = json.dumps(d)
    assert "image_t2i" in s
    assert "dispatch_cli" in s
    assert "tartarus" in s


def test_receipt_round_trip_equal():
    rr = _sample_run_result()
    g1 = GenerationReceipt(
        receipt_id="rcpt_1_X_image_t2i",
        modality="image_t2i",
        caller_id="test",
        project="tartarus",
        episode=1,
        shot_id="X",
        timestamp_utc="2026-04-27T03:14:15Z",
        run_result=rr,
        provenance={"a": 1, "b": [1, 2]},
        eval_scores={"gemini_flash": 0.92},
    )
    g2 = GenerationReceipt.from_dict(g1.to_dict())
    assert g1 == g2


def test_receipt_round_trip_with_failure_run_result():
    rr = RunResult(
        id="X_image_t2i_FAIL",
        modality="image_t2i",
        output_path=None,
        metadata={"final_state": "failed", "cost_usd": 0.0, "gate_verdict": None,
                  "take_index": None, "model": None, "pipeline": None},
        success=False,
        error="upstream API down",
    )
    g1 = GenerationReceipt(
        receipt_id="rcpt_1_X_image_t2i",
        modality="image_t2i",
        caller_id="test",
        project=None,
        episode=None,
        shot_id="X",
        timestamp_utc="2026-04-27T03:14:15Z",
        run_result=rr,
    )
    g2 = GenerationReceipt.from_dict(g1.to_dict())
    assert g1 == g2
    assert g2.run_result.success is False
    assert g2.run_result.error == "upstream API down"


def test_receipt_id_unique_per_microsecond():
    a = make_receipt_id("X", "image_t2i")
    b = make_receipt_id("X", "image_t2i")
    # microsecond resolution can collide in the same call burst; allow either
    assert a.startswith("rcpt_")
    assert b.startswith("rcpt_")
    assert a.endswith("_image_t2i")


def test_receipt_id_handles_none_shot():
    rid = make_receipt_id(None, "audio_t2a")
    assert "unknown" in rid
    assert rid.endswith("_audio_t2a")


def test_receipt_frozen():
    rr = _sample_run_result()
    g = GenerationReceipt(
        receipt_id="x", modality="image_t2i", caller_id="test",
        project=None, episode=None, shot_id=None,
        timestamp_utc="2026-04-27T03:14:15Z", run_result=rr,
    )
    with pytest.raises(Exception):
        g.caller_id = "tampered"  # type: ignore
