"""W19B-2: background_prompt v7 opt-in — minimal focused tests.

LLM / image / VLM API call 0 (build_bg_user_prompt 만 호출). DB / ImageAsset 0.
"""
from __future__ import annotations

import pytest

from app.modules.pipeline.background_prompt import (
    BackgroundPromptOverlayError,
    _CLEAN_BG_SENTINEL,
    build_bg_user_prompt,
)


def _bg_spec():
    return {
        "bg_id": "L01B01",
        "loc_id": "L01",
        "sub_location": "primary_unit",
        "state_label_raw": "day_norm",
        "applies_to_shots": ["S1_Shot1"],
    }


_OVERLAY_DIRTY = {
    "bg_id": "L01B01",
    "fp_id": "fp_a",
    "use_numbered_elements": [1, 2],
    "ignore_numbered_elements": [3],
    "base_markers_to_reference": [
        {
            "number": 1,
            "label": "primary unit",
            "category": "area",
            "position_hint": "center",
            "base_layer_decision": "base_structural_unit",
        }
    ],
    "transient_markers_to_describe": [
        {
            "number": 2,
            "label": "scattered debris",
            "category": "prop",
            "position_hint": "north wall floor",
            "base_layer_decision": "state_overlay_transient_object",
        }
    ],
    "ignored_state_overlay_markers": [
        {
            "number": 3,
            "label": "ghost cue",
            "category": "prop",
            "position_hint": "east wall",
            "base_layer_decision": "state_overlay_plot_cue",
        }
    ],
    "target_unit_marker_numbers": [1],
    "dominant_target_unit_marker_number": 1,
    "clean_background_expected": False,
    "diagnostics": [],
}

_OVERLAY_CLEAN = {
    "bg_id": "L01B01",
    "fp_id": "fp_a",
    "use_numbered_elements": [1],
    "ignore_numbered_elements": [2],
    "base_markers_to_reference": [
        {
            "number": 1,
            "label": "primary unit",
            "category": "area",
            "position_hint": "center",
            "base_layer_decision": "base_structural_unit",
        }
    ],
    "transient_markers_to_describe": [],
    "ignored_state_overlay_markers": [
        {
            "number": 2,
            "label": "ghost cue",
            "category": "prop",
            "position_hint": "north wall",
            "base_layer_decision": "state_overlay_plot_cue",
        }
    ],
    "target_unit_marker_numbers": [1],
    "dominant_target_unit_marker_number": 1,
    "clean_background_expected": True,
    "diagnostics": [],
}


def test_v6_default_selector_renders_without_overlay():
    """v6 default 는 overlay 없이 동작 + flat numbered_elements_block 그대로."""
    rendered = build_bg_user_prompt(
        bg_spec=_bg_spec(),
        floor_plan_path="/p/fp.png",
        prior_bg_paths=[],
        scene_segments=[],
        visual_world_rules="",
        numbered_elements=[
            {
                "number": 1,
                "label": "primary unit",
                "category": "area",
                "position_hint": "center",
            }
        ],
        source_language="ko",
    )
    assert "1. primary unit [area] — center" in rendered
    assert "{base_markers_block}" not in rendered
    assert "{transient_markers_block}" not in rendered


def test_v7_missing_overlay_raises():
    with pytest.raises(BackgroundPromptOverlayError, match="received None"):
        build_bg_user_prompt(
            bg_spec=_bg_spec(),
            floor_plan_path="/p/fp.png",
            prior_bg_paths=[],
            scene_segments=[],
            visual_world_rules="",
            source_language="ko",
            prompt_version="7",
            overlay_payload=None,
        )


def test_v7_dirty_separates_base_and_transient_ignored_absent():
    rendered = build_bg_user_prompt(
        bg_spec=_bg_spec(),
        floor_plan_path="/p/fp.png",
        prior_bg_paths=[],
        scene_segments=[],
        visual_world_rules="",
        source_language="ko",
        prompt_version="7",
        overlay_payload=_OVERLAY_DIRTY,
    )
    # base 와 transient 가 각각 marker line 으로 렌더링.
    assert "1. primary unit [area] — center" in rendered
    assert "2. scattered debris [prop] — north wall floor" in rendered
    # ignored marker (#3 ghost cue) 는 number / label 모두 누출 X.
    assert "ghost cue" not in rendered
    assert "3. " not in rendered  # marker line 형식으로 등장 X.
    # clean sentinel 은 dirty BG 에 없어야.
    assert _CLEAN_BG_SENTINEL not in rendered


def test_v7_clean_emits_sentinel_ignored_absent():
    rendered = build_bg_user_prompt(
        bg_spec=_bg_spec(),
        floor_plan_path="/p/fp.png",
        prior_bg_paths=[],
        scene_segments=[],
        visual_world_rules="",
        source_language="ko",
        prompt_version="7",
        overlay_payload=_OVERLAY_CLEAN,
    )
    assert "1. primary unit [area] — center" in rendered
    assert _CLEAN_BG_SENTINEL in rendered
    # ignored marker (#2 ghost cue) 누출 X.
    assert "ghost cue" not in rendered
    assert "2. ghost cue" not in rendered
