"""zoom-crop 경로 로깅 컨텍스트 계약 (P0c, 2026-06-18).

generate_continuity_crop_png 이 generate_image 전에 gemini_client 로깅 컨텍스트를
설정하는지 검증한다 — 안 하면 worker thread 의 stale/empty ctx 로 log_llm_call 이
호출돼 llm_call_log 에 누락/오귀속(S12sh15 결손). VLM/crop 은 monkeypatch
(deterministic wiring 만 검증; 이미지 품질은 실측 영역).
"""
import io

from PIL import Image

import app.services.zoom_continuity_render_service as zc


class _RecordingClient:
    def __init__(self):
        self.ctx_calls = []

    def set_context(self, **kw):
        self.ctx_calls.append(kw)
        return self

    def generate_image(self, prompt, labeled_references=None):
        return (b"PNGBYTES", 5)


def _png_bytes(w=1280, h=720):
    buf = io.BytesIO()
    Image.new("RGB", (w, h), (40, 40, 40)).save(buf, "PNG")
    return buf.getvalue()


def _stub_internals(monkeypatch, tmp_path):
    from app.core import config as _cfg
    monkeypatch.setattr(_cfg.settings, "projects_dir", str(tmp_path))
    monkeypatch.setattr(zc, "vlm_locate_bbox", lambda *a, **k: {"bbox": [0.1, 0.1, 0.9, 0.9]})
    monkeypatch.setattr(zc, "assess_viability", lambda bbox: {"found": True})
    monkeypatch.setattr(zc, "expand_crop_16x9", lambda size, bbox: (0, 0, size[0], size[1]))


def test_zoom_crop_sets_scene_image_gen_log_context(monkeypatch, tmp_path):
    _stub_internals(monkeypatch, tmp_path)
    client = _RecordingClient()
    png, prompt, diag = zc.generate_continuity_crop_png(
        project_id="P", episode_id="E", scene_index=12, shot_index=15,
        zoom_target={"group_id": "g", "source": [[12, 9]]},
        gemini_client=client, source_bytes=_png_bytes(),
    )
    assert png == b"PNGBYTES"
    assert client.ctx_calls, "set_context 가 호출되지 않음 (로그 누락 회귀)"
    ctx = client.ctx_calls[-1]
    assert ctx["operation_type"] == "scene_image_gen"
    assert ctx["scene_index"] == 12
    assert ctx["shot_index"] == 15
    assert ctx["project_id"] == "P" and ctx["episode_id"] == "E"


def test_zoom_crop_trace_meta_overrides(monkeypatch, tmp_path):
    _stub_internals(monkeypatch, tmp_path)
    client = _RecordingClient()
    zc.generate_continuity_crop_png(
        project_id="P", episode_id="E", scene_index=12, shot_index=15,
        zoom_target={"group_id": "g", "source": [[12, 9]]},
        gemini_client=client, source_bytes=_png_bytes(),
        trace_meta={"operation_type": "single_scene_image_gen", "still_id": "sid-1"},
    )
    ctx = client.ctx_calls[-1]
    # 단건 regen caller 가 operation_type override + still_id 주입
    assert ctx["operation_type"] == "single_scene_image_gen"
    assert ctx["still_id"] == "sid-1"
    assert ctx["scene_index"] == 12 and ctx["shot_index"] == 15
