"""★★★나가는 질의가 **선언된 좌표**를 실었나 (Codex GO 2026-09-02 · 가).

실측으로 갈라 센 것 —
  · **우리가 만든** 검색어 50개 중 좌표 빠진 것 **0**
  · **provider 가 스스로 더한** 질의 200개 중 좌표 빠진 것 **195**

그래서 문은 **우리 것에만** 건다. provider 확장은 우리가 만드는 것이 아니라
관측값이다.

계약: 런타임 구조화 칸만 · 선언된 것만 · 지역만 있으면 현대도 지역은 의무 ·
시대가 없으면 만들지도 요구하지도 않는다 · 뜻을 짐작하지 않는다.
"""
from __future__ import annotations

import pytest

from app.modules.pipeline import reference_acquisition_rounds as rr

ERA = "가나다 무렵의 어떤 시기"
REGION = "라마바 지방의 도시"


class TestOnlyWhatIsDeclaredIsRequired:
    def test_both_declared_and_both_carried_passes(self):
        got = rr.assert_coordinates_carried(
            f"{ERA} {REGION} 의 어떤 것을 찾아라",
            [f"어떤 것 사진 {ERA} {REGION}"],
            coordinates={"era": ERA, "region": REGION})
        assert got["declared"] == ["era", "region"]
        assert got["checked"] == 2

    def test_a_missing_region_stops(self):
        with pytest.raises(rr.CoordinatesMissing, match="region"):
            rr.assert_coordinates_carried(
                f"{ERA} 의 어떤 것", [f"어떤 것 {ERA}"],
                coordinates={"era": ERA, "region": REGION})

    def test_a_missing_era_stops(self):
        with pytest.raises(rr.CoordinatesMissing, match="era"):
            rr.assert_coordinates_carried(
                f"{REGION} 의 어떤 것", [f"어떤 것 {REGION}"],
                coordinates={"era": ERA, "region": REGION})

    def test_region_alone_is_mandatory_and_era_is_not_invented(self):
        """★★현대 원고 — 시대 선언이 **없다**. 지역만 의무다."""
        got = rr.assert_coordinates_carried(
            f"{REGION} 의 어떤 가게", [f"어떤 가게 {REGION}"],
            coordinates={"era": "", "region": REGION})
        assert got["declared"] == ["region"], "★없는 시대를 요구했다"

        with pytest.raises(rr.CoordinatesMissing, match="region"):
            rr.assert_coordinates_carried("어떤 가게", ["어떤 가게 사진"],
                                          coordinates={"era": "",
                                                       "region": REGION})

    def test_nothing_declared_requires_nothing(self):
        got = rr.assert_coordinates_carried("아무 말", ["아무 질의"],
                                            coordinates={"era": "",
                                                         "region": ""})
        assert got["declared"] == []

    def test_it_checks_every_term_not_just_the_first(self):
        with pytest.raises(rr.CoordinatesMissing, match="검색어 2"):
            rr.assert_coordinates_carried(
                f"{REGION} 의 어떤 것",
                [f"어떤 것 {REGION}", "좌표 없는 두 번째 질의"],
                coordinates={"region": REGION})

    def test_an_empty_term_is_not_a_violation(self):
        got = rr.assert_coordinates_carried(
            f"{REGION} 의 것", [f"것 {REGION}", "", "   "],
            coordinates={"region": REGION})
        assert got["declared"] == ["region"]


class TestItDoesNotGuessMeaning:
    """★뜻을 짐작하면 그것이 곧 하드코딩이다 — **선언된 문자열**만 본다."""

    def test_a_paraphrase_does_not_pass(self):
        """★★비슷한 말은 통과 못 한다 — 동의어 표를 두는 순간 하드코딩이다."""
        with pytest.raises(rr.CoordinatesMissing):
            rr.assert_coordinates_carried(
                "라마바 근처 도시의 어떤 것", ["어떤 것 라마바 근처"],
                coordinates={"region": REGION})

    def test_nothing_is_compared_against_a_literal(self):
        """★★검사에 쓰이는 값은 **선언된 것**뿐이어야 한다.

        문자열을 하나라도 질의와 견주면 그 순간 목록이 생긴다. 글자로
        찾지 말고 **`in` 비교의 왼쪽이 상수인지**를 본다.
        """
        import ast
        import inspect

        src = inspect.getsource(rr.assert_coordinates_carried)
        bad = []
        for n in ast.walk(ast.parse(src)):
            if not isinstance(n, ast.Compare):
                continue
            for op, right in zip(n.ops, n.comparators):
                if isinstance(op, (ast.In, ast.NotIn)) and \
                        isinstance(n.left, ast.Constant):
                    bad.append((ast.dump(n.left), ast.dump(right)[:40]))
        assert bad == [], f"★상수를 질의와 견준다 — 목록이 생겼다: {bad}"
        assert "import re" not in src and "regex" not in src.lower()

    def test_a_coordinate_nobody_could_have_hardcoded_works(self):
        """★음성 대조 — 지어낸 좌표도 그대로 작동한다(목록이 없다는 증거)."""
        made_up = "쿼르툼 제9순환기 · 하위구역 42"
        got = rr.assert_coordinates_carried(
            f"{made_up} 의 무엇", [f"무엇 {made_up}"],
            coordinates={"era": made_up})
        assert got["declared"] == ["era"]
        with pytest.raises(rr.CoordinatesMissing):
            rr.assert_coordinates_carried("무엇", ["무엇 사진"],
                                          coordinates={"era": made_up})


class TestTheGateStandsBeforeTheProvider:
    def test_a_bad_brief_never_reaches_search(self, tmp_path):
        """★★★공개 끝점 — 저작기가 좌표를 빠뜨리면 **검색이 안 불린다**."""
        called = {"search": 0}

        def _search(**_kw):
            called["search"] += 1
            return {"queries": [], "images": []}

        def _writer(_target, *, narrow=False):
            return {"search_directive_native": "좌표 없는 지시문",
                    "search_terms_native": ["좌표 없는 질의"],
                    "language_lock_native": "그 나라 말로만"}

        _writer.coordinates = {"era": ERA, "region": REGION}
        got = rr.acquire_one(
            {"subject_id": "rs_x", "directive_native": "d",
             "terms_native": ["t"], "language_lock_native": "l"},
            workdir=tmp_path / "w", rel_root=tmp_path,
            search=_search, download=lambda *a, **k: True,
            judge=lambda c: {}, write_brief=_writer, rounds=1)
        assert called["search"] == 0, "★좌표 없는 질의가 나갔다"
        assert got["status"] == "retryable"
        assert "좌표" in json_of(got), got["rounds"][0].get("decision")

    def test_a_good_brief_passes_and_is_recorded(self, tmp_path):
        seen = {}

        def _search(**kw):
            seen.update(kw)
            return {"queries": [[kw["terms_native"][0]]], "images": []}

        def _writer(_t, *, narrow=False):
            return {"search_directive_native": f"{ERA} {REGION} 의 것",
                    "search_terms_native": [f"것 {ERA} {REGION}"],
                    "language_lock_native": "그 나라 말로만"}

        _writer.coordinates = {"era": ERA, "region": REGION}
        got = rr.acquire_one(
            {"subject_id": "rs_x", "directive_native": "d",
             "terms_native": ["t"], "language_lock_native": "l"},
            workdir=tmp_path / "w", rel_root=tmp_path,
            search=_search, download=lambda *a, **k: True,
            judge=lambda c: {}, write_brief=_writer, rounds=1)
        assert seen, "★검색이 안 불렸다 — 이 시험이 아무것도 안 잠근다"
        rep = got["rounds"][0]["coordinates_carried"]
        assert rep["declared"] == ["era", "region"]


def json_of(x):
    import json

    return json.dumps(x, ensure_ascii=False, default=str)


class TestProviderExpansionIsObservedNotGated:
    """★★(나) — provider 가 더한 질의는 **관측**이지 문이 아니다.

    실측: 우리가 준 50개는 좌표를 50/50 실었고, provider 가 더한 200개 중
    195개에 좌표가 없었다. 그 둘을 **합쳐 센 수**는 acceptance 근거가 아니다.
    """

    def test_it_separates_ours_from_the_providers(self):
        got = rr.query_provenance(
            sent=[f"것 {ERA} {REGION}"],
            searched=[[f"것 {ERA} {REGION}", "site:어딘가 것", "것 사진"]],
            coordinates={"era": ERA, "region": REGION})
        assert got["provided"] == 1
        assert got["expanded"] == 2
        assert [q["origin"] for q in got["queries"]] == [
            rr.ORIGIN_PROVIDED, rr.ORIGIN_EXPANDED, rr.ORIGIN_EXPANDED]

    def test_it_counts_the_expansion_loss_separately(self):
        got = rr.query_provenance(
            sent=[f"것 {ERA} {REGION}"],
            searched=[[f"것 {ERA} {REGION}", "site:어딘가 것",
                       f"것 {REGION}"]],
            coordinates={"era": ERA, "region": REGION})
        assert got["expanded_without"] == {"era": 2, "region": 1}
        assert "provided" in got and got["provided"] == 1, (
            "★합쳐 세면 우리 쪽 0/50 이 안 보인다")

    def test_it_never_gates(self):
        """★확장에 좌표가 하나도 없어도 **예외가 안 난다**."""
        got = rr.query_provenance(sent=["아무것"],
                                  searched=[["전혀 다른 질의"]],
                                  coordinates={"era": ERA})
        assert got["expanded_without"] == {"era": 1}

    def test_a_candidate_without_a_binding_is_unknown_not_guessed(self,
                                                                  tmp_path):
        """★★provider 가 결속을 안 주면 **모른다**로 남긴다 — 안 짐작한다."""
        def _search(**kw):
            return {"queries": [[kw["terms_native"][0]]],
                    "images": [{"image_url": "https://x.invalid/1.jpg",
                                "thumbnail_url": "", "caption": "설명",
                                "source_website_url": ""}]}

        def _writer(_t, *, narrow=False):
            return {"search_directive_native": f"{ERA} {REGION} 의 것",
                    "search_terms_native": [f"것 {ERA} {REGION}"],
                    "language_lock_native": "그 나라 말로만"}

        _writer.coordinates = {"era": ERA, "region": REGION}

        def _dl(_u, dest, _t=""):
            dest.parent.mkdir(parents=True, exist_ok=True)
            dest.write_bytes(b"\x89PNG\r\n\x1a\n")
            return True

        got = rr.acquire_one(
            {"subject_id": "rs_x", "directive_native": "d",
             "terms_native": ["t"], "language_lock_native": "l"},
            workdir=tmp_path / "w", rel_root=tmp_path, search=_search,
            download=_dl, judge=lambda c: {}, write_brief=_writer, rounds=1)
        cands = got["rounds"][0]["downloaded_candidates"]
        assert cands and cands[0]["query_origin"] == rr.ORIGIN_UNKNOWN
        prov = got["rounds"][0]["query_provenance"]
        assert prov["provided"] == 1 and prov["expanded"] == 0
