"""참조 묶음 **유료 canary 의 문**. ★유료 0.

Codex 2026-08-31 —

> 고정 샷에서 production 조립이 만든 `N = 기존 refs + content-hash dedupe 된
> grounding refs` 를 preflight expected **exact count** 로 잠그고,
> plan/provider/model/base refs/sidecar identity 가 바뀌거나 실제 N 이 다르면
> **provider 전에 섭니다**. provider cap 이 선언돼 있으면 N 과 대조하고,
> 없으면 **임의 상한을 발명하지 말고** observed N 과 acceptance 를 기록합니다.
> canary authorization 은 여전히 **image dispatch 1회**.
"""
from __future__ import annotations

import pytest

from tools.grounding_audit import bundle_canary_preflight as pf

REFS = [("배경판", b"plate"), ("맥락", b"ctx"), ("상세", b"det")]
META = [("background", "L01B01"),
        ("background", "grounding:LP01:context:x"),
        ("background", "grounding:LP01:detail:y")]
ROLES = ["background_chain_ref", "background_general",
         "grounding_part_detail_ref"]
REQ = [("background", "grounding:LP01:context:x"),
       ("background", "grounding:LP01:detail:y")]


def _pre(**over):
    kw = {"labeled_refs": REFS, "attached_meta": META, "ref_roles": ROLES,
          "sidecar_required": REQ}
    kw.update(over)
    return pf.preflight(**kw)


class TestItLocksWhatMatters:
    def test_the_lock_has_every_axis(self):
        lock = _pre()["lock"]
        for k in ("reference_count", "sidecar_required", "image_dispatch",
                  "outbound"):
            assert k in lock, f"★{k} 가 잠금에 없다"
        # ★나가는 것은 **한 벌**이다 — 두 자리에 다시 안 적는다
        for k in ("reference_shas", "roles", "attached", "capability",
                  "labels", "role_metadata", "prompt_sha", "shot"):
            assert k in lock["outbound"], f"★{k} 가 나가는 한 벌에 없다"

    def test_the_image_dispatch_is_one(self):
        """★이미지 생성은 **한 번**이다 — 참조 장수와 별개."""
        assert _pre()["lock"]["image_dispatch"] == 1
        assert pf.APPROVED_IMAGE_DISPATCH == 1

    def test_the_bytes_themselves_are_folded(self):
        """★★같은 장수라도 **다른 사진**이면 다른 판이다."""
        a = _pre()["lock"]
        b = _pre(labeled_refs=[("배경판", b"plate"), ("맥락", b"ctx"),
                               ("상세", b"OTHER")])["lock"]
        assert a["reference_count"] == b["reference_count"]
        assert a != b, "★사진이 바뀌었는데 잠금이 같다"

    def test_it_is_deterministic(self):
        assert _pre()["lock"] == _pre()["lock"]


class TestItStopsWhenTheApprovedThingChanges:
    @pytest.mark.parametrize("over", [
        {"labeled_refs": REFS[:2], "attached_meta": META[:2],
         "ref_roles": ROLES[:2]},                       # 장수가 줄었다
        {"ref_roles": ["background_chain_ref", "background_general",
                       "grounding_context_detail_ref"]},  # 역할이 바뀌었다
        {"sidecar_required": REQ[:1]},                    # 요구가 바뀌었다
        {"attached_meta": META[:2] + [("background", "다른값")]},
    ])
    def test_a_changed_plan_stops(self, over):
        approved = _pre()["lock"]
        with pytest.raises(pf.CanaryScopeMismatch):
            _pre(approved_lock=approved, **over)

    def test_the_same_plan_passes(self):
        approved = _pre()["lock"]
        assert _pre(approved_lock=approved)["ok"] is True

    def test_no_approved_lock_means_first_run(self):
        """★첫 판은 잠글 것이 아직 없다 — 그때 낸 것이 승인 대상이 된다."""
        assert _pre(approved_lock=None)["ok"] is True


class TestTheCountComesFromTheClient:
    """★설정 사본이 아니라 **실제 client instance** 가 낸다."""

    def test_the_provider_is_the_scene_image_one(self):
        """★실측: 씬 이미지는 Gemini, cine 변환은 따로다 — **다른 경로**."""
        got = _pre()["count"]
        assert got["provider"] == "GeminiImageClient"
        assert got["model"], "★모델이 안 실렸다"

    def test_an_unknown_max_is_recorded_not_invented(self):
        """★★`None` 은 「모른다」다 — 상한을 **발명하지 않고 기록**한다."""
        got = _pre()["count"]
        assert got["declared_max"] is None
        assert got["observed"] == len(REFS)

    def test_a_declared_max_would_be_enforced(self):
        """★선언이 있으면 **대조**한다 — 그 갈래도 살아 있다."""
        cap = {"provider": "X", "model": "m", "supports_labeled_refs": True,
               "min_images": 0, "max_images": 2}
        pf.assert_count_ok(cap, 2)
        from app.modules.pipeline.grounding_reference_bundle import (
            ReferenceCountRefused)

        with pytest.raises(ReferenceCountRefused):
            pf.assert_count_ok(cap, 3)

    def test_the_client_is_read_not_copied(self):
        """★registry 를 베끼면 두 벌이 된다 — instance 에게 묻는지 본다."""
        import inspect

        src = inspect.getsource(pf.preflight)
        assert "capability_of(" in src, "★client 에게 안 묻는다"
        assert "max_images" not in src, "★상한을 여기서 다시 적는다"


class TestItBuysNothing:
    def test_the_module_never_generates(self):
        """★이 파일은 **문**이다 — 굽는 것은 runner 가 한다."""
        import ast
        import inspect

        tree = ast.parse(inspect.getsource(pf))
        called = {getattr(n.func, "attr", getattr(n.func, "id", ""))
                  for n in ast.walk(tree) if isinstance(n, ast.Call)}
        assert not (called & {"generate_image", "generate_and_validate_scene",
                              "completion", "create"}), \
            f"★굽는 것을 부른다: {sorted(called)}"
