"""근거 문장은 **검증된 언급이 있는 씬** 것만 남는다 (Codex BLOCK 1, 2026-09-02 밤).

씬 1 의 언급만 검증된 행에 씬 2 의 실제 문장이 근거로 붙으면, 다른 자리의 겉모습이
이 행의 payload 에 실린다. 좌표로만 가른다 — 그 문장이 검증된 언급 씬 어디에도 없으면
**그 문장만** 빼고 사유를 적는다(행째 격리는 안 한다: 실측 골목 행이 씬 4 언급 없이
씬 4 근거만 적은 「덜 적음」이었다). 지어낸 근거는 여전히 행째 격리.
"""
from __future__ import annotations

from app.modules.pipeline import grounding_chunk as gc


def _segs():
    from tests.grounding.fixtures import synthetic_episode as ep
    return ep.segment_texts()


def _sentence_only_in(segs, sid, avoid):
    """`sid` 에만 있는 글 조각 하나 — 다른 씬에는 없는 것으로 고른다."""
    text = segs[sid]
    for start in range(0, max(1, len(text) - 12)):
        piece = text[start:start + 12]
        if piece.strip() and all(piece not in segs[o] for o in avoid):
            return piece
    raise AssertionError("씬 고유 조각을 못 찾았다")


def _row(mentions, evidence):
    return {"owner_type": "prop", "surface_form": "x",
            "mentions": mentions, "evidence_quotes": list(evidence),
            "hard_to_generate": True, "viewers_would_notice": True,
            "visual_brief": "", "search_terms_native": ["가"], "language_lock_native": ""}


def test_evidence_from_another_scene_is_dropped_and_recorded():
    segs = _segs()
    other = _sentence_only_in(segs, "scene-2", ["scene-1"])
    got = gc.resolve_rows([_row([{"mention_quote": "가방", "occurrence_index": 1}], [other])],
                          chunk_id="c0", segment_ids=["scene-1", "scene-2"], segments=segs)
    assert got["quarantined"] == []
    r = got["rows"][0]
    assert r["evidence_quotes"] == [], "★다른 씬의 근거가 이 행에 붙었다"
    p = r["salvage_problems"][0]
    assert p["kind"] == gc.Q_EVIDENCE_SCENE and p["where"] == ["scene-2"]


def test_evidence_in_a_verified_scene_is_kept():
    segs = _segs()
    own = _sentence_only_in(segs, "scene-1", ["scene-2"])
    got = gc.resolve_rows([_row([{"mention_quote": "가방", "occurrence_index": 1}], [own])],
                          chunk_id="c0", segment_ids=["scene-1", "scene-2"], segments=segs)
    r = got["rows"][0]
    assert r["evidence_quotes"] == [own] and "salvage_problems" not in r


def test_a_row_mentioned_in_both_scenes_keeps_both_scenes_evidence():
    segs = _segs()
    a = _sentence_only_in(segs, "scene-1", ["scene-2"])
    b = _sentence_only_in(segs, "scene-2", ["scene-1"])
    word2 = next(w for w in ("가방", "문", "창", "벽", "길", "손", "바닥") if w in segs["scene-2"])
    got = gc.resolve_rows([_row([{"mention_quote": "가방", "occurrence_index": 1},
                                 {"mention_quote": word2, "occurrence_index": 1}], [a, b])],
                          chunk_id="c0", segment_ids=["scene-1", "scene-2"], segments=segs)
    r = got["rows"][0]
    scenes = {o["source_span"]["segment_id"] for o in r["occurrences"]}
    if scenes == {"scene-1", "scene-2"}:
        assert r["evidence_quotes"] == [a, b]
    else:   # 낱말이 씬 1 에서 먼저 잡히면 씬 2 근거만 빠진다 — 좌표 규칙 그대로
        assert a in r["evidence_quotes"]


def test_a_fabricated_evidence_sentence_still_quarantines_the_row():
    segs = _segs()
    got = gc.resolve_rows([_row([{"mention_quote": "가방", "occurrence_index": 1}], ["원고 어디에도 없는 문장"])],
                          chunk_id="c0", segment_ids=["scene-1", "scene-2"], segments=segs)
    assert got["rows"] == [] and got["quarantined"][0]["problems"][0]["kind"] == gc.Q_EVIDENCE
