"""build_distinctive_trait_block — evidence-gate 순수 계약 테스트 (② P0a, 2026-06-18).

deterministic 게이트만 검증한다 (LLM 의 literal/metaphor 분류 품질은 dry-run 실측
영역). 게이트 규칙: source_quote 비어있지 않음 AND interpretation_kind ==
'literal_visual' 인 항목만 t2i context 블록으로 weave, 나머지는 excluded.
"""
from app.core.steps.entity_steps import build_distinctive_trait_block


def _t(trait, quote, kind, attr="", ttype="eye_color", reason=""):
    return {
        "trait": trait, "source_quote": quote, "attribution_note": attr,
        "trait_type": ttype, "interpretation_kind": kind,
        "interpretation_reason": reason,
    }


def test_literal_visual_with_quote_is_woven():
    block, excluded = build_distinctive_trait_block(
        [_t("red eyes", "남자의 붉은 눈동자", "literal_visual", attr="본문 남자=이 인물")]
    )
    assert "red eyes" in block
    assert "남자의 붉은 눈동자" in block
    assert "본문 남자=이 인물" in block  # attribution_note 가 있으면 연결근거 노출
    assert excluded == []


def test_metaphorical_impression_is_excluded_even_with_quote():
    block, excluded = build_distinctive_trait_block(
        [_t("golden eyes", "금빛 물결이 일렁이는 눈동자", "metaphorical_impression")]
    )
    assert block == ""  # 근거(quote)가 있어도 비유면 렌더 미반영
    assert len(excluded) == 1
    assert excluded[0]["interpretation_kind"] == "metaphorical_impression"


def test_ambiguous_is_excluded():
    block, excluded = build_distinctive_trait_block(
        [_t("pale skin", "창백한", "ambiguous", ttype="skin")]
    )
    assert block == ""
    assert len(excluded) == 1


def test_literal_visual_without_quote_is_excluded():
    block, excluded = build_distinctive_trait_block(
        [_t("green eyes", "", "literal_visual")]
    )
    assert block == ""
    assert len(excluded) == 1


def test_empty_and_none_return_empty():
    assert build_distinctive_trait_block([]) == ("", [])
    assert build_distinctive_trait_block(None) == ("", [])


def test_mixed_keeps_only_literal_with_quote():
    block, excluded = build_distinctive_trait_block([
        _t("red eyes", "붉은 눈동자", "literal_visual"),
        _t("golden eyes", "금빛 물결이 일렁이는 눈동자", "metaphorical_impression"),
        _t("wrist mark", "손목의 작은 원", "literal_visual", ttype="marking"),
        _t("scar", "", "literal_visual", ttype="scar"),
    ])
    assert "red eyes" in block and "wrist mark" in block
    assert "golden eyes" not in block and "scar" not in block
    assert len(excluded) == 2  # metaphor + no-quote


def test_attribution_omitted_when_blank():
    block, _ = build_distinctive_trait_block(
        [_t("white hair", "흰 백발", "literal_visual", attr="", ttype="hair_color")]
    )
    assert "white hair" in block
    assert "연결근거" not in block  # attribution_note 빈 문자열이면 연결근거 안 붙음
