"""shot_run_uid 가 **실제 sink** 를 타고 pipeline_metadata_json 까지 가는가.

★2026-08-24 Codex BLOCK 1. 내 앞선 시험은 ternary 만 재연해서
「호출자가 값을 고른다」까지만 봤다 — 그런데 ImageAsset 생성자에는 그런 칸이
없고 annotate 는 `_build_lineage_annotation` 이 만든 meta 만 merge 하므로,
그 사이에서 값이 통째로 버려지고 있었다. **조립하는 자리가 아니라 나가는
자리를 재야 한다.**
"""
import json

from app.services.image_capture.annotate import annotate_generated_asset
from app.services.scene_persistence_service import ScenePersistenceService


class _Asset:
    """ImageAsset 대역 — annotate 가 만지는 칸만 있다."""

    def __init__(self):
        self.input_image_ids = None
        self.generation_call_id = None
        self.pipeline_metadata_json = None


def _svc():
    svc = ScenePersistenceService.__new__(ScenePersistenceService)
    svc._project_id = "p"
    svc._db = None
    # post-hoc resolve 두 곳은 DB 를 타므로 이 시험에서는 통과만 시킨다.
    svc._resolve_registered_guide_asset_ids = lambda u, e: ([], [], list(u))
    svc._resolve_prev_frame_asset_ids = lambda u, e: ([], [], list(u))
    return svc


def _annotated(scene_result):
    """실제 경로 그대로: _build_lineage_annotation → annotate → json."""
    svc = _svc()
    _ids, _call, meta = svc._build_lineage_annotation(
        scene_result, scene_result.get("episode_id"), "single_scene_image_gen")
    asset = _Asset()
    annotate_generated_asset(
        asset, pipeline_role="scene_still", stage="scene_image",
        input_image_ids=(_ids or None), pipeline_metadata=meta,
    )
    return json.loads(asset.pipeline_metadata_json or "{}")


def _scene_result(**over):
    base = {
        "still_id": "s-1", "episode_id": "e-1",
        "actual_attached_image_ids": [], "actual_attached_refs": [],
        "unresolved_attached_refs": [], "generation_call_id": "call-1",
    }
    base.update(over)
    return base


def test_produced_visit_stamps_uid_on_the_asset():
    """★만든 방문 — uid 가 pipeline_metadata_json 에 실제로 남아야 한다."""
    meta = _annotated(_scene_result(shot_run_uid="0190-made-it"))
    assert meta["shot_run_uid"] == "0190-made-it"


def test_reused_visit_leaves_no_uid_key():
    """재사용 방문 — 호출자가 None 을 준다. 키 자체가 없어야 한다.

    남기면 「이 자산을 만든 것」이 거짓이 된다 — 만든 것은 이전 주행이다.
    """
    meta = _annotated(_scene_result(shot_run_uid=None))
    assert "shot_run_uid" not in meta


def test_absent_key_is_byte_identical_to_before():
    """키를 아예 안 준 경로(배치 등)는 기존 meta 와 같아야 한다."""
    meta = _annotated(_scene_result())
    assert "shot_run_uid" not in meta
    assert meta["reference_lineage_source"] == "input_image_ids_actual_attached"


def test_uid_does_not_clobber_other_meta():
    meta = _annotated(_scene_result(
        shot_run_uid="0190-x",
        unresolved_attached_refs=[{"role": "cine_source_sel", "stage": "fix"}],
    ))
    assert meta["shot_run_uid"] == "0190-x"
    assert meta["unresolved_attached_refs"][0]["stage"] == "fix"
