"""Area #5 v1 — sidecar phantom guard tests.

scene_detail v26 producer 가 emit 한 `reference_phrase_kinds` 가
validate_attached_refs step 6 의 새 sidecar exact compare 진입점.
legacy classify_from_the_reference 폐기 후 test class.
"""
import pytest
from app.core.ref_contract_validator import validate_attached_refs, RefContractError


def _make_rpc(required_refs=None, readiness=None):
    """sidecar tests 의 _make_rpc default — readiness=None 으로 step 5 (readiness_policy
    consistency) 우회. step 6 sidecar 만 검사. step 5 readiness behavior 검사 test 는
    explicit non-empty required_refs + readiness="block_if_missing" 전달.
    """
    return {
        "asset_requirements": {
            "required_refs": required_refs or [],
            "readiness_policy": readiness,
        }
    }


def test_sidecar_character_declared_with_meta_passes():
    """character kind declared + attached character_outlook 1+ — PASS"""
    validate_attached_refs(
        _make_rpc(),
        labeled_refs=[("Reference image 1 — character C01: outlook O01", b"\x89PNG" * 10)],
        attached_meta=[("character_outlook", "C01O01")],
        prompt="the character shown in image 1 holds an item",
        is_close_framing=False,
        reference_phrase_kinds=["character"],
    )  # no exception = PASS


def test_sidecar_character_declared_without_meta_fails():
    """character kind declared + attached_meta has no character — RefContractError"""
    with pytest.raises(RefContractError, match="reference_phrase_kinds declares kind='character'"):
        validate_attached_refs(
            _make_rpc(),
            labeled_refs=[("Reference image 1 — background L01", b"\x89PNG" * 10)],
            attached_meta=[("background", "L01")],
            prompt="some prompt",
            is_close_framing=False,
            reference_phrase_kinds=["character"],
        )


def test_sidecar_background_declared_close_framing_with_meta_passes():
    """background kind declared + close framing + attached background meta — PASS (strict exact compare)"""
    validate_attached_refs(
        _make_rpc(),
        labeled_refs=[("Reference image 1 — background L01", b"\x89PNG" * 10)],
        attached_meta=[("background", "L01")],
        prompt="some prompt",
        is_close_framing=True,
        reference_phrase_kinds=["background"],
    )  # no exception — C2 fix: step 6 ignores close-framing skip


def test_sidecar_background_declared_close_framing_without_meta_fails():
    """background kind declared + close framing + no background meta — RefContractError (C2 fix: legacy skip 폐기)"""
    with pytest.raises(RefContractError, match="reference_phrase_kinds declares kind='background'"):
        validate_attached_refs(
            _make_rpc(),
            labeled_refs=[("Reference image 1 — character C01: outlook O01", b"\x89PNG" * 10)],
            attached_meta=[("character_outlook", "C01O01")],
            prompt="close-up of subject's hand",
            is_close_framing=True,  # legacy: skipped. C2 fix: still fails.
            reference_phrase_kinds=["background"],
        )


def test_sidecar_prop_declared_with_meta_passes():
    """prop kind declared + attached prop meta — PASS"""
    validate_attached_refs(
        _make_rpc(),
        labeled_refs=[("Reference image 1 — prop P01", b"\x89PNG" * 10)],
        attached_meta=[("prop", "P01")],
        prompt="the object shown in image 1",
        is_close_framing=False,
        reference_phrase_kinds=["prop"],
    )  # PASS


def test_sidecar_empty_array_passes():
    """empty reference_phrase_kinds array — no phantom check, step 6 passes"""
    validate_attached_refs(
        _make_rpc(),
        labeled_refs=[],
        attached_meta=[],
        prompt="generic prompt body without reference attribution",
        is_close_framing=False,
        reference_phrase_kinds=[],
    )  # PASS


def test_sidecar_missing_kwarg_raises_typeerror():
    """reference_phrase_kinds keyword arg 누락 — TypeError (keyword-only required, no default)"""
    with pytest.raises(TypeError, match="reference_phrase_kinds"):
        validate_attached_refs(
            _make_rpc(),
            labeled_refs=[],
            attached_meta=[],
            prompt="x",
            is_close_framing=False,
            # reference_phrase_kinds 누락
        )


def test_sidecar_none_raises_refcontracterror():
    """reference_phrase_kinds=None — RefContractError (No Silent Fallback)"""
    with pytest.raises(RefContractError, match="reference_phrase_kinds missing"):
        validate_attached_refs(
            _make_rpc(),
            labeled_refs=[],
            attached_meta=[],
            prompt="x",
            is_close_framing=False,
            reference_phrase_kinds=None,
        )


def test_sidecar_invalid_enum_value_raises():
    """reference_phrase_kinds 안 invalid enum value — RefContractError"""
    with pytest.raises(RefContractError, match="reference_phrase_kinds invalid enum value"):
        validate_attached_refs(
            _make_rpc(),
            labeled_refs=[],
            attached_meta=[],
            prompt="x",
            is_close_framing=False,
            reference_phrase_kinds=["face"],  # invalid (allowed: character/background/prop)
        )


def test_sidecar_non_list_type_raises():
    """reference_phrase_kinds non-list type — RefContractError"""
    with pytest.raises(RefContractError, match="reference_phrase_kinds malformed"):
        validate_attached_refs(
            _make_rpc(),
            labeled_refs=[],
            attached_meta=[],
            prompt="x",
            is_close_framing=False,
            reference_phrase_kinds="character",  # str, not list
        )


def test_sidecar_multiple_kinds_all_validated():
    """multiple kinds declared — 모든 kind 가 attached meta 와 strict compare"""
    # character + background 둘 다 declared, 둘 다 attached
    validate_attached_refs(
        _make_rpc(),
        labeled_refs=[
            ("Reference image 1 — character C01: outlook O01", b"\x89PNG" * 10),
            ("Reference image 2 — background L01", b"\x89PNG" * 10),
        ],
        attached_meta=[("character_outlook", "C01O01"), ("background", "L01")],
        prompt="x",
        is_close_framing=False,
        reference_phrase_kinds=["character", "background"],
    )  # PASS

    # character + background declared, only character attached
    with pytest.raises(RefContractError, match="kind='background'"):
        validate_attached_refs(
            _make_rpc(),
            labeled_refs=[("Reference image 1 — character C01: outlook O01", b"\x89PNG" * 10)],
            attached_meta=[("character_outlook", "C01O01")],
            prompt="x",
            is_close_framing=False,
            reference_phrase_kinds=["character", "background"],
        )
