"""P8 Inc2-b — state-variant ref 가 required character 를 충족하는지 (validator step 3b).

근본: bare C## immobilized subject(시신 등)는 resolver section 2.5 가 base passport
대신 dead/injured variant bytes 를 attach 하며 meta 를 ("character_state","C##:state")
로 기록한다. 이는 같은 캐릭터의 더 구체적인 reference 이므로 required character
("character","C##") 를 sid prefix 매칭으로 충족시킨다.

★2026-07-02 계약 정정: character_outlook required(step 3)도 같은 base 캐릭터의
character_state 로 충족한다 — 기존 "orthogonal(의상 vs 상태)" 계약은 resolver 의
composite→state 대체와 데드락 (S12 sh10 production 실측: 시신 shot 에서
required C16O10 vs attached ('character_state','C16:dead') 가 영구 hard-block).
살아있는 outfit composite 를 시신 shot 에 강제 부착하는 것이 오히려 정체성 모순.
다른 캐릭터의 state 는 여전히 충족 X.

(원본 test_p8_inc2b_state_variant_required_char.py 는 stash 미포함[untracked 유실]이라
재작성. resolver section 2.5 라이브 거동은 regen acceptance 로 검증.)
"""
from __future__ import annotations

import pytest

from app.core.ref_contract_validator import RefContractError, validate_attached_refs


def _rpc(required_refs):
    return {"asset_requirements": {"required_refs": required_refs}}


def test_inc2b_character_state_satisfies_required_character():
    """required character C04 ← attached ("character_state","C04:dead") sid prefix 충족."""
    validate_attached_refs(
        _rpc([{"kind": "character", "id": "C04", "policy": "required"}]),
        [("character C04 — dead state reference", b"x")],
        [("character_state", "C04:dead")],
        prompt="the immobilized body lies on the bed",
        is_close_framing=False,
        reference_phrase_kinds=[],
    )


def test_inc2b_base_character_meta_still_satisfies_required_character():
    """회귀: 평소 base ("character","C04") attach 는 그대로 충족 (변경 없음)."""
    validate_attached_refs(
        _rpc([{"kind": "character", "id": "C04", "policy": "required"}]),
        [("character C04 appearance reference", b"x")],
        [("character", "C04")],
        prompt="a standing person",
        is_close_framing=False,
        reference_phrase_kinds=[],
    )


def test_inc2b_wrong_sid_character_state_does_not_satisfy():
    """다른 인물 state-variant 는 required character 를 충족 X → RefContractError."""
    with pytest.raises(RefContractError):
        validate_attached_refs(
            _rpc([{"kind": "character", "id": "C04", "policy": "required"}]),
            [("character C09 — dead state reference", b"x")],
            [("character_state", "C09:dead")],
            prompt="the body",
            is_close_framing=False,
            reference_phrase_kinds=[],
        )


def test_inc2b_character_outlook_satisfied_by_same_char_state():
    """★2026-07-02 정정: required character_outlook(C04O02)은 같은 base 캐릭터의
    character_state("C04:dead")로 충족 — immobilized resolver 대체와의 데드락 해소."""
    validate_attached_refs(
        _rpc([{"kind": "character_outlook", "id": "C04O02", "policy": "required"}]),
        [("character C04 — dead state reference", b"x")],
        [("character_state", "C04:dead")],
        prompt="the body in its dark uniform",
        is_close_framing=False,
        reference_phrase_kinds=[],
    )


def test_inc2b_character_outlook_not_satisfied_by_other_char_state():
    """다른 캐릭터의 character_state 는 required character_outlook 충족 X."""
    with pytest.raises(RefContractError):
        validate_attached_refs(
            _rpc([{"kind": "character_outlook", "id": "C04O02", "policy": "required"}]),
            [("character C09 — dead state reference", b"x")],
            [("character_state", "C09:dead")],
            prompt="the body in its dark uniform",
            is_close_framing=False,
            reference_phrase_kinds=[],
        )
