"""W21B-wave-4 C4 (part 2): background_prompt v12 projection-plate consumer.

v12 = v10 contract verbatim + a single ``{projection_card_plate_block}``
placeholder fed by the projection-card guard (part 1,
``resolve_projection_plate_injection``). When a verified anchor plate prose is
injected, it surfaces as the authoritative same-space ground-truth reference;
when absent, a clean sentinel keeps the prompt byte-faithful to v10 inference.
opt-in selector, production default unchanged ("6"). LLM/image/VLM/DB I/O 0.
"""
from __future__ import annotations

from app.modules.pipeline.background_prompt import (
    PROMPT_VERSION_MAP,
    build_bg_user_prompt,
    resolve_prompt_version,
)
from app.modules.prompt_loader import load_prompt, load_schema


_V12_PACK_NAME = "12.202605310513"

_PLATE_PROSE = (
    "좁은 옥탑방 실내, 색바랜 벽지와 낡은 장판 바닥, 커튼으로 가린 침구 공간, "
    "오래 사용한 알루미늄 새시 창과 낮은 천장."
)


def _bg_spec(surface_role: str = "interior_room"):
    return {
        "bg_id": "L05B07",
        "loc_id": "L05",
        "sub_location": "rooftop room interior",
        "state_label_raw": "day interior plate",
        "surface_role": surface_role,
        "applies_to_shots": ["S5_Shot7"],
    }


_OVERLAY = {
    "bg_id": "L05B07",
    "fp_id": "fp_l05_main",
    "use_numbered_elements": [1, 4],
    "ignore_numbered_elements": [3],
    "base_markers_to_reference": [
        {
            "number": 1,
            "label": "shared living zone",
            "category": "area",
            "position_hint": "center",
            "base_layer_decision": "base_structural_unit",
            "render_role": "structural_skeleton",
            "top_down_legibility": "clear",
        },
    ],
    "transient_markers_to_describe": [
        {
            "number": 3,
            "label": "scattered debris",
            "category": "prop",
            "position_hint": "north wall floor",
            "base_layer_decision": "state_overlay_plot_cue",
            "render_role": "not_applicable",
            "top_down_legibility": "not_applicable",
        }
    ],
    "ignored_state_overlay_markers": [],
    "target_unit_marker_numbers": [1, 4],
    "dominant_target_unit_marker_number": None,
    "clean_background_expected": False,
    "diagnostics": [],
}


def test_v12_selector_resolves_pack_name():
    assert PROMPT_VERSION_MAP["12"] == _V12_PACK_NAME
    assert resolve_prompt_version("12") == _V12_PACK_NAME


def test_v12_pack_adds_projection_block_keeps_v10_shape():
    system = load_prompt("background_prompt", "system", version=_V12_PACK_NAME)
    user_template = load_prompt(
        "background_prompt", "user_template", version=_V12_PACK_NAME,
    )
    schema = load_schema("background_prompt", "schema", version=_V12_PACK_NAME)

    # 새 projection plate 계약 존재.
    assert "Anchor projection plate" in system
    assert "{projection_card_plate_block}" in user_template
    # v10 contract 보존 (screen guard / purity / template / output shape).
    assert "news anchor" in system
    assert "{transient_markers_block}" not in user_template
    assert set(schema["required"]) == {
        "bg_id",
        "t2i_prompt",
        "ref_guide",
        "shot_guides",
        "objects_owned_by_background",
    }


def test_v12_injects_plate_prose_when_provided():
    rendered = build_bg_user_prompt(
        bg_spec=_bg_spec(),
        floor_plan_path="/tmp/fp_l05_main.png",
        prior_bg_paths=[],
        scene_segments=[
            {"scene_index": 5, "heading": "probe", "text": "VERBATIM_SCENE_PROBE_LINE"}
        ],
        visual_world_rules="regional world rule body",
        source_language="ko",
        prompt_version="12",
        overlay_payload=_OVERLAY,
        projection_plate_prose=_PLATE_PROSE,
    )
    # plate prose 가 projection block 에 그대로 surface.
    assert _PLATE_PROSE in rendered
    assert "Anchor projection plate" in rendered
    # base markers / surface_role 는 v10 그대로.
    assert "1. shared living zone" in rendered
    assert "surface_role: interior_room" in rendered
    # v10 purity 보존: transient label / scene 본문 누설 X.
    assert "scattered debris" not in rendered
    assert "VERBATIM_SCENE_PROBE_LINE" not in rendered


def test_v12_clean_sentinel_when_no_plate():
    rendered = build_bg_user_prompt(
        bg_spec=_bg_spec(),
        floor_plan_path="/tmp/fp_l05_main.png",
        prior_bg_paths=[],
        scene_segments=[],
        visual_world_rules="regional world rule body",
        source_language="ko",
        prompt_version="12",
        overlay_payload=_OVERLAY,
        projection_plate_prose=None,
    )
    # placeholder 가 치환되어 sentinel 노출 (placeholder leak X).
    assert "{projection_card_plate_block}" not in rendered
    assert "(none" in rendered
    assert _PLATE_PROSE not in rendered


def test_v12_fp_less_exterior_allows_missing_overlay():
    rendered = build_bg_user_prompt(
        bg_spec=_bg_spec("exterior_plate"),
        floor_plan_path="",
        prior_bg_paths=[],
        scene_segments=[],
        visual_world_rules="regional exterior rule",
        source_language="ko",
        prompt_version="12",
        overlay_payload=None,
        projection_plate_prose=None,
    )
    assert "surface_role: exterior_plate" in rendered
    assert "fp-less surface plate" in rendered
    # projection block 은 fp-less 에서도 sentinel 로 치환.
    assert "{projection_card_plate_block}" not in rendered


def test_v12_base_markers_byte_match_v10_when_no_plate():
    """projection plate 없는 v12 의 base-marker 블록은 v10 과 동일 직렬화."""
    common = dict(
        bg_spec=_bg_spec(),
        floor_plan_path="/tmp/fp_l05_main.png",
        prior_bg_paths=[],
        scene_segments=[],
        visual_world_rules="regional world rule body",
        source_language="ko",
        overlay_payload=_OVERLAY,
    )
    v10 = build_bg_user_prompt(prompt_version="10", **common)
    v12 = build_bg_user_prompt(
        prompt_version="12", projection_plate_prose=None, **common
    )
    # base markers 블록 라인은 두 버전에서 동일 직렬화.
    marker_line = (
        "1. shared living zone [area, structural_skeleton, legibility=clear] — center"
    )
    assert marker_line in v10
    assert marker_line in v12
