"""Task B2 — GeminiImageClient.generate_image capture 계측 테스트.

gemini generate_image 은 ~10 호출자(reference/scene 최종물 + composition guide 등
중간물)가 통과하는 choke-point. capture 는 generation_context scope 가 열렸을 때만
저장(default-off) → 최종 reference/scene 경로(scope 미개방)는 중복 0.

폐기되던 success-path log_llm_call 반환값(call_id)을 회수해 generation_call_id 에 넣는다.
"""

from unittest.mock import MagicMock

from app.services.image_capture.context import generation_context
from app.services.image_capture.queue import CAPTURE_DIAG

_PAYLOAD = b"GEMINIPNG" * 8  # 72 bytes


class _FakeResp:
    def __enter__(self):
        return self

    def __exit__(self, *a):
        return False

    def read(self):
        import base64
        import json

        b64 = base64.b64encode(_PAYLOAD).decode("ascii")
        return json.dumps(
            {"candidates": [{"content": {"parts": [{"inlineData": {"data": b64}}]}}]}
        ).encode()


def _setup(monkeypatch, *, call_id="call-xyz"):
    import app.modules.llm.gemini_image_client as gi

    monkeypatch.setattr(gi, "log_llm_call", lambda **kw: call_id)
    fake_tracer = MagicMock()
    fake_tracer.log = MagicMock()
    monkeypatch.setattr(
        "app.modules.llm.image_tracer.get_image_tracer", lambda: fake_tracer
    )
    monkeypatch.setattr(gi.urllib.request, "urlopen", lambda req, timeout=None: _FakeResp())
    return gi.GeminiImageClient(api_key="dummy-key", model="gemini-3.1-flash-image-preview")


def test_gemini_captures_inside_scope_with_call_id(monkeypatch):
    client = _setup(monkeypatch, call_id="call-xyz")
    with generation_context("p-gem", "e-gem", "scene_image") as q:
        png, _ms = client.generate_image(prompt="a scene")
        assert png == _PAYLOAD  # decode 1회, 바이트 그대로 반환
        assert len(q._items) == 1
        _spool, meta = q._items[0]
        assert meta["prompt"] == "a scene"
        assert meta["generation_call_id"] == "call-xyz"
        assert meta["pipeline_role"]  # role 부착됨


def test_gemini_no_capture_outside_scope_duplicate_zero(monkeypatch):
    """scope 미개방(=최종 reference/scene 경로) → capture 0, 중복 0 보장."""
    client = _setup(monkeypatch)
    before = CAPTURE_DIAG["skipped_no_context"]
    png, _ms = client.generate_image(prompt="final ref")
    assert png == _PAYLOAD  # production 경로도 정상 반환
    assert CAPTURE_DIAG["skipped_no_context"] >= before + 1


def test_gemini_labels_not_in_input_image_ids(monkeypatch):
    """ref label 문자열은 input_image_ids(UUID lineage SOT)에 넣지 않는다(Codex BLOCKING).

    gemini_image_client 의 ref_image_ids 는 사람이 읽는 라벨이지 image_asset UUID 가
    아니므로, input_image_ids(=UUID lineage SOT)에 넣으면 Phase D edge 가 오염된다.
    라벨은 pipeline_metadata['reference_labels'] 에만(표시/진단용).
    """
    client = _setup(monkeypatch)
    with generation_context("p-gl", "e-gl", "scene_image") as q:
        client.generate_image(
            prompt="edit",
            labeled_references=[("Reference: hero face", b"imgbytes")],
        )
        assert len(q._items) == 1
        _spool, meta = q._items[0]
        assert meta["input_image_ids"] is None  # 라벨을 UUID lineage 로 넣지 않음
        assert meta["pipeline_metadata"]["reference_labels"] == ["Reference: hero face"]
