"""FINDING 6 W4b (e2e-bughunt-v1) — base_id_required outlook-form canonicalization.

scene_detail 11-shot crash 중 5 shot 의 root cause = scene_detail gemini-pro 가
`base_id_required` 정책 subject 에 outlook 복합 ID `C##O##` 를 t2i_prompt 에
써서 `visible_entities_validator` 가 `outlook_forbidden` 으로 raise.

`canonicalize_base_id_required_outlook_forms` = base_id_required base 에 한해
exact word-boundary regex 로 `C##O##` → `C##` deterministic 치환. 다른 정책
subject 의 outlook form / prose 숫자 / 유사 token 은 무영향.

no live LLM + NO VLM — 순수 helper 함수 검증.
"""
from __future__ import annotations

import re

from app.core.subject_reference_policy import (
    canonicalize_base_id_required_outlook_forms,
)

# visible_entities_validator._ENTITY_ID_PATTERN 와 동일 — canonical 결과가
# validator 의 outlook 탐지를 통과함을 검증 (outlook_forbidden 회피).
_ENTITY_ID_PATTERN = re.compile(r"\b(C\d{2,3}(?:O\d{2,3})?)\b")


# ── G1 — base_id_required subject 의 outlook form → base form ──
def test_g1_base_required_outlook_stripped():
    text = "A figure C07O02 stands by the door."
    assert canonicalize_base_id_required_outlook_forms(text, {"C07"}) == (
        "A figure C07 stands by the door."
    )


def test_g1_multiple_occurrences_same_base():
    text = "C07O02 on the left, C07O11 on the right."
    assert canonicalize_base_id_required_outlook_forms(text, {"C07"}) == (
        "C07 on the left, C07 on the right."
    )


def test_g1_three_digit_outlook():
    text = "Close-up of C07O123 face."
    assert canonicalize_base_id_required_outlook_forms(text, {"C07"}) == (
        "Close-up of C07 face."
    )


# ── G2 — 다른 정책 subject 의 outlook form 보존 ──
def test_g2_non_base_required_outlook_preserved():
    # C02 는 base_required set 에 없음 (id_and_outlook_required 등) → 보존.
    text = "C07O02 talks to C02O05 in the room."
    out = canonicalize_base_id_required_outlook_forms(text, {"C07"})
    assert out == "C07 talks to C02O05 in the room."


# ── G3 — 유사 token / prose 숫자 / 다른 char ID 무영향 ──
def test_g3_no_false_match_on_similar_tokens():
    # C0702 (O 없음) / C070 / C17O02 (다른 base) / prose 0702 — 전부 무영향.
    text = "C0702 and C070 and C17O02 and item 0702 and C07."
    assert canonicalize_base_id_required_outlook_forms(text, {"C07"}) == text


def test_g3_other_base_outlook_untouched():
    text = "C17O02 enters."
    assert canonicalize_base_id_required_outlook_forms(text, {"C07"}) == text


# ── G4 — edge: empty / no base / malformed base ──
def test_g4_empty_text():
    assert canonicalize_base_id_required_outlook_forms("", {"C07"}) == ""


def test_g4_empty_base_set():
    text = "C07O02 here"
    assert canonicalize_base_id_required_outlook_forms(text, set()) == text


def test_g4_malformed_base_skipped():
    # base 가 순수 C## form 이 아니면 skip (defensive no-op).
    text = "C07O02 here"
    assert canonicalize_base_id_required_outlook_forms(text, {"C07O02"}) == text
    assert canonicalize_base_id_required_outlook_forms(text, {"garbage"}) == text


# ── G5 — 복수 base_id_required subject ──
def test_g5_multiple_base_required_subjects():
    text = "C07O02 meets C04O09 at the gate."
    out = canonicalize_base_id_required_outlook_forms(text, {"C07", "C04"})
    assert out == "C07 meets C04 at the gate."


# ── G6 — canonical 결과가 validator outlook 탐지를 통과 ──
def test_g6_canonical_prompt_has_no_outlook_for_base():
    # validate_visible_entities_contract 의 outlook_forbidden 은 t2i_prompt 의
    # _ENTITY_ID_PATTERN 매치 중 f"{base}O" prefix 로 outlook 사용을 탐지한다.
    # canonicalize 후엔 base 에 대한 outlook form 이 0 이어야 통과.
    raw = "A cropped C07O02 hand reaches for C02O05."
    canonical = canonicalize_base_id_required_outlook_forms(raw, {"C07"})
    used_ids = set(_ENTITY_ID_PATTERN.findall(canonical))
    # C07 base 에 대한 outlook form 없음 → outlook_forbidden 미발생.
    assert not any(sid.startswith("C07O") for sid in used_ids)
    assert "C07" in used_ids
    # base_required 아닌 C02 의 outlook 은 보존.
    assert "C02O05" in used_ids
