"""FINDING C W2 (Category A) — background over-declaration consumer normalization.

W0 triage: scene_detail LLM 이 [L##: ...] free-form location 묘사 블록을 보고
per-variation sidecar reference_phrase_kinds 에 'background' 를 over-declare
할 수 있다. background ref attach 여부는 coordinator runtime SOT (chain_bg map
lookup + build_prev_shot_background_ref) — producer 가 예측 불가. attached_meta
가 확정된 consumer boundary 에서 normalize.

strip 3-조건: (1) reference_phrase_kinds 에 'background' 있음 (2) attached_meta
에 ('background',*)/('background_prev_shot',*) 없음 (3) required_refs 에
kind='background' 없음. 조건 3 = genuine missing required background 는 mask
안 함 (validator step 4 가 step 6 전에 fail-fast).

대상 실패 still: 96cb0479 S2.1 (background_binding.mode=not_applicable,
[L02:] free-form 블록). Gates G1-G7.
"""
from __future__ import annotations

import pytest

from app.core.errors import StaleUpstreamError
from app.core.ref_contract_validator import validate_attached_refs
from app.services.scene_generation_coordinator import (
    _normalize_background_phrase_kind,
)


# ── G1: strip — bg declared, no bg attached, no bg required ────────────
def test_g1_strip_when_no_background_attached() -> None:
    """background 선언 + attached_meta 에 bg 없음 + required_refs 에 bg 없음
    → 'background' strip."""
    result = _normalize_background_phrase_kind(
        reference_phrase_kinds=["background"],
        attached_meta=[],
        rpc={"asset_requirements": {"required_refs": []}},
    )
    assert result == []


# ── G2: keep — ('background', L##) attached ───────────────────────────
def test_g2_keep_when_background_attached() -> None:
    """attached_meta 에 ('background', L##) 있으면 'background' 유지."""
    result = _normalize_background_phrase_kind(
        reference_phrase_kinds=["background"],
        attached_meta=[("background", "L04B07")],
        rpc={"asset_requirements": {"required_refs": []}},
    )
    assert result == ["background"]


# ── G3: keep — ('background_prev_shot', loc) attached ─────────────────
def test_g3_keep_when_background_prev_shot_attached() -> None:
    """attached_meta 에 ('background_prev_shot', loc) 있으면 'background' 유지."""
    result = _normalize_background_phrase_kind(
        reference_phrase_kinds=["background"],
        attached_meta=[("background_prev_shot", "L04")],
        rpc={"asset_requirements": {"required_refs": []}},
    )
    assert result == ["background"]


# ── G4: keep — required_refs has background (don't mask) ──────────────
def test_g4_keep_when_required_background_present() -> None:
    """required_refs 에 kind='background' 있으면 strip 금지 — genuine missing
    required background 는 validator step 4 가 fail-fast 해야 한다."""
    result = _normalize_background_phrase_kind(
        reference_phrase_kinds=["background"],
        attached_meta=[],
        rpc={"asset_requirements": {"required_refs": [
            {"kind": "background", "id": "L04B07", "policy": "required"},
        ]}},
    )
    assert result == ["background"]


# ── G4b: required background no-mask — validator still fail-fast ──────
def test_g4b_required_background_not_masked_validator_raises() -> None:
    """required_refs 에 background 가 있고 미attach 면, normalize 가 strip 안 해
    'background' 가 유지되고 validator 가 fail-fast 한다 (guard 가 genuine
    missing required background 를 mask 하지 않음 증명 — Codex plan review 권고).
    chain bg id (L##B## form) 는 BG_ID_RE 매칭 → step 4 가 StaleUpstreamError."""
    rpc = {"asset_requirements": {"required_refs": [
        {"kind": "background", "id": "L04B07", "policy": "required"},
    ]}}
    normalized = _normalize_background_phrase_kind(
        reference_phrase_kinds=["background"],
        attached_meta=[],
        rpc=rpc,
    )
    assert normalized == ["background"]
    with pytest.raises(StaleUpstreamError):
        validate_attached_refs(
            rpc, labeled_refs=[], attached_meta=[],
            prompt="A wide shot.", is_close_framing=False,
            reference_phrase_kinds=normalized,
        )


# ── G5: unchanged — no background in reference_phrase_kinds ───────────
def test_g5_unchanged_when_no_background_declared() -> None:
    """reference_phrase_kinds 에 background 없으면 무변경."""
    result = _normalize_background_phrase_kind(
        reference_phrase_kinds=["character"],
        attached_meta=[],
        rpc={"asset_requirements": {"required_refs": []}},
    )
    assert result == ["character"]


# ── G6: partial strip — keep character/prop, strip background ────────
def test_g6_strip_background_keep_others() -> None:
    """background 만 strip, character/prop 은 유지."""
    result = _normalize_background_phrase_kind(
        reference_phrase_kinds=["character", "background", "prop"],
        attached_meta=[("prop", "P03")],
        rpc={"asset_requirements": {"required_refs": [
            {"kind": "prop", "id": "P03", "policy": "required"},
        ]}},
    )
    assert result == ["character", "prop"]


# ── G7: repro — case 1 (96cb0479) end-to-end ─────────────────────────
def test_g7_finding_c_case1_repro_no_violation() -> None:
    """실패 still 96cb0479 재현: background_binding.mode=not_applicable,
    required_refs=[], attached_meta=[], reference_phrase_kinds=['background']
    → normalize 후 validator step 6 통과 (RefContractError 0)."""
    rpc = {"asset_requirements": {"required_refs": [], "readiness_policy": "not_applicable"}}
    normalized = _normalize_background_phrase_kind(
        reference_phrase_kinds=["background"],
        attached_meta=[],
        rpc=rpc,
    )
    assert normalized == []
    # normalize 결과로 validator 호출 — phantom guard 통과.
    validate_attached_refs(
        rpc, labeled_refs=[], attached_meta=[],
        prompt="A wide shot. [L02: a wet ground].",
        is_close_framing=False,
        reference_phrase_kinds=normalized,
    )
