"""world_context — 세계관 CP → 프롬프트 블록 조립 계약.

이 모듈은 "야외 장소 이미지가 국적 없이 나온다"는 실측 결함의 고침
자체다(야외 경로에만 세계관이 한 글자도 도달하지 않았다). 조립 결과가
곧 이미지·저작 프롬프트의 세계 사실이므로, 무엇을 싣고 무엇을 빼는지가
계약이다 — 특히 PLACE_RULE_TYPES 필터(인물/현상 규칙 제외)는 이 필터가
조용히 넓어지면 무관 장소까지 오염된다.

CP 는 전부 픽스처(SAMPLE_FIXTURE_*) — 시나리오 의존 0.
"""

SAMPLE_FIXTURE_VWR = {
    "data": {
        "region": "SAMPLE_FIXTURE_REGION",
        "era": "SAMPLE_FIXTURE_ERA",
        "rules": [
            {"rule_type": "architecture",
             "description": "SAMPLE_FIXTURE_ARCH_DESC",
             "visual_guideline": "SAMPLE_FIXTURE_ARCH_GUIDE"},
            {"rule_type": "environment",
             "description": "SAMPLE_FIXTURE_ENV_DESC",
             "visual_guideline": "SAMPLE_FIXTURE_ENV_GUIDE"},
            # 인물/현상 계열 — 장소 이미지 블록에서 제외 대상
            {"rule_type": "body_deformation",
             "description": "SAMPLE_FIXTURE_BODY_DESC",
             "visual_guideline": "SAMPLE_FIXTURE_BODY_GUIDE"},
            {"rule_type": "projection",
             "description": "SAMPLE_FIXTURE_PROJ_DESC",
             "visual_guideline": "SAMPLE_FIXTURE_PROJ_GUIDE"},
        ],
    }
}


# ── build_world_facts_block: 이미지 프롬프트용(필터 있음) ─────────────


def test_world_facts_block_includes_region_era_and_place_rules_only():
    from app.core.world_context import build_world_facts_block

    block = build_world_facts_block(SAMPLE_FIXTURE_VWR)
    # 행 전수 고정 — 부분 문자열 부재 나열은 규칙 종류가 늘 때마다
    # 빠뜨린다. 이 한 줄이 순서·접두·필터를 동시에 잠근다.
    assert block.splitlines() == [
        "- Region (real-world reference): SAMPLE_FIXTURE_REGION",
        "- Era: SAMPLE_FIXTURE_ERA",
        "- SAMPLE_FIXTURE_ARCH_GUIDE",
        "- SAMPLE_FIXTURE_ENV_GUIDE",
    ]
    # 실린 것은 visual_guideline 뿐 — description 은 이미지 프롬프트에
    # 들어가지 않는다(서술 원문 재주입 금지)
    assert "SAMPLE_FIXTURE_ARCH_DESC" not in block


def test_world_facts_block_filter_is_the_declared_rule_types():
    """PLACE_RULE_TYPES 가 이 블록의 중심 필터 — 값 자체를 리터럴로 고정.

    상수를 그대로 되읽어 기대값을 만들면 항등식이라 필터가 넓어져도
    초록이다(인물/현상 규칙이 장소 T2I 로 새는 경로가 그것이다).
    """
    from app.core.world_context import (
        PLACE_RULE_TYPES,
        build_world_facts_block,
    )

    assert PLACE_RULE_TYPES == (
        "time_period", "technology", "architecture", "environment",
        "culture")
    # 선언 밖 종류는 단 한 줄도 실리지 않는다
    for rtype in ("body_deformation", "projection", "SAMPLE_FIXTURE_UNKNOWN"):
        assert build_world_facts_block({"data": {"rules": [{
            "rule_type": rtype,
            "visual_guideline": "SAMPLE_FIXTURE_EXCLUDED_GUIDE"}]}}) == ""
    # 선언 안 종류는 전부 실린다
    for rtype in PLACE_RULE_TYPES:
        assert build_world_facts_block({"data": {"rules": [{
            "rule_type": rtype,
            "visual_guideline": "SAMPLE_FIXTURE_INCLUDED_GUIDE"}]}}) == (
            "- SAMPLE_FIXTURE_INCLUDED_GUIDE")


def test_world_facts_block_empty_when_no_usable_facts():
    """CP 부재·빈 값 = 빈 문자열 (호출부 byte-identical 전제).

    호출부(lane Step1)는 이 블록이 비면 fail-closed 로 배경 생성을 막는
    다 — 빈 문자열이 곧 '사실 없음' 신호라 degrade 모양이 계약이다.
    """
    from app.core.world_context import build_world_facts_block

    assert build_world_facts_block(None) == ""
    assert build_world_facts_block({}) == ""
    assert build_world_facts_block({"data": None}) == ""
    assert build_world_facts_block({"data": {}}) == ""
    # 공백만 있는 값·guideline 없는 규칙·비 dict 규칙 = 무기여
    assert build_world_facts_block({"data": {
        "region": "   ", "era": "",
        "rules": [
            {"rule_type": "architecture", "visual_guideline": "  "},
            {"rule_type": "architecture",
             "description": "SAMPLE_FIXTURE_DESC_ONLY"},
            "SAMPLE_FIXTURE_NOT_A_DICT",
        ],
    }}) == ""
    # region 만 있어도 블록은 성립한다 (era/규칙 결손 관용)
    assert build_world_facts_block({"data": {
        "region": "SAMPLE_FIXTURE_REGION"}}) == (
        "- Region (real-world reference): SAMPLE_FIXTURE_REGION")


# ── build_world_rules_text: 저작 LLM 용(필터 없음) ────────────────────


def test_world_rules_text_includes_every_rule_type():
    """저작 LLM 은 관련성 판단을 스스로 하므로 rule_type 필터가 없다 —
    이미지 블록과 **다른 계약**이라는 점을 값으로 고정한다."""
    from app.core.world_context import build_world_rules_text

    text = build_world_rules_text(SAMPLE_FIXTURE_VWR)
    assert text.splitlines() == [
        "지역: SAMPLE_FIXTURE_REGION",
        "시대: SAMPLE_FIXTURE_ERA",
        "[architecture] SAMPLE_FIXTURE_ARCH_DESC",
        "  시각 지침: SAMPLE_FIXTURE_ARCH_GUIDE",
        "[environment] SAMPLE_FIXTURE_ENV_DESC",
        "  시각 지침: SAMPLE_FIXTURE_ENV_GUIDE",
        # 이미지 블록이 걸러내는 인물/현상 규칙도 여기엔 실린다
        "[body_deformation] SAMPLE_FIXTURE_BODY_DESC",
        "  시각 지침: SAMPLE_FIXTURE_BODY_GUIDE",
        "[projection] SAMPLE_FIXTURE_PROJ_DESC",
        "  시각 지침: SAMPLE_FIXTURE_PROJ_GUIDE",
    ]


def test_world_rules_text_degrades_and_tolerates_partial_rules():
    from app.core.world_context import build_world_rules_text

    assert build_world_rules_text(None) == ""
    assert build_world_rules_text({}) == ""
    assert build_world_rules_text({"data": {"rules": []}}) == ""
    # rule_type 없는 규칙=접두 없음, guideline 없는 규칙=지침 줄 없음,
    # desc/guideline 둘 다 없는 규칙=행 자체 없음, 비 dict=무시
    assert build_world_rules_text({"data": {"rules": [
        {"description": "SAMPLE_FIXTURE_NO_TYPE"},
        {"rule_type": "technology", "description": "SAMPLE_FIXTURE_TECH"},
        {"rule_type": "culture", "visual_guideline": "SAMPLE_FIXTURE_CUL"},
        {"rule_type": "environment"},
        "SAMPLE_FIXTURE_NOT_A_DICT",
    ]}}).splitlines() == [
        "SAMPLE_FIXTURE_NO_TYPE",
        "[technology] SAMPLE_FIXTURE_TECH",
        "[culture]",
        "  시각 지침: SAMPLE_FIXTURE_CUL",
    ]
