"""W19A — FloorPlanPromptStep selector / _config_hash / unknown-value guard.

본 test 는 *production-side* test layout (review §6.6 lock). 다음 3 가지만 본다.

1. ``settings.floor_plan_prompt_version`` selector default ("5") 가
   ``_resolved_prompt_version()`` 을 통해 기존 PROMPT_VERSION constant 와
   동일한 v5 pack 이름으로 풀린다 → 결과 ``_config_hash`` 가
   "수정 전" v5 hash 와 byte-identical (default-v5 checkpoint 보존).
2. selector "6" opt-in 시 ``_resolved_prompt_version()`` 이 v6 pack 이름으로
   풀리고, ``_config_hash`` 가 v5 와 다른 값을 stamp 한다 (opt-in 만 새로운
   hash).
3. unknown selector 가 ``ValueError`` 로 fail-fast → silent shift 방지.

image API / LLM API / VLM API 호출 0. DB / ImageAsset write 0.
"""
from __future__ import annotations

import hashlib
import json as _json
from unittest.mock import patch

import pytest

from app.core.steps.floor_plan_prompt_step import (
    PROMPT_VERSION,
    SCHEMA_VERSION,
    FloorPlanPromptStep,
    _resolved_prompt_version,
)
from app.modules.pipeline.floor_plan_prompt import PROMPT_VERSION_MAP


V5_PACK = PROMPT_VERSION_MAP["5"]  # "5.202605201406"
V6_PACK = PROMPT_VERSION_MAP["6"]  # "6.202605262300"


def _expected_hash(*, background_mode: str, prompt_version: str) -> str:
    payload = {
        "background_mode": background_mode,
        "schema_version": SCHEMA_VERSION,
        "prompt_version": prompt_version,
    }
    return hashlib.sha256(
        _json.dumps(payload, sort_keys=True).encode("utf-8")
    ).hexdigest()[:16]


def _new_step() -> FloorPlanPromptStep:
    """StepRunner __init__ 우회 — _config_hash 만 검증."""
    return FloorPlanPromptStep.__new__(FloorPlanPromptStep)


# ----- 1. selector default == legacy v5 hash -----


def test_module_constant_pinned_to_v5_pack_name():
    """``PROMPT_VERSION`` backward-compat: v5 pack 이름과 lock-step."""
    assert PROMPT_VERSION == V5_PACK


def test_resolved_prompt_version_default_returns_v5_pack():
    with patch("app.core.config.settings.floor_plan_prompt_version", "5"):
        assert _resolved_prompt_version() == V5_PACK


def test_config_hash_default_v5_byte_identical_with_legacy():
    """default selector "5" + background_mode="on" → 수정 전 v5 hash 와 동일.

    review §4.3 (opt-in only) 의 핵심 invariant.
    """
    with patch("app.core.config.settings.background_mode", "on"), \
         patch("app.core.config.settings.floor_plan_prompt_version", "5"):
        step = _new_step()
        got = step._config_hash()
    assert got == _expected_hash(background_mode="on", prompt_version=V5_PACK)


def test_config_hash_default_v5_with_floor_plan_anchored_alias():
    """background_mode='floor_plan_anchored' 도 동일 default-v5 hash 가 stable."""
    with patch("app.core.config.settings.background_mode", "floor_plan_anchored"), \
         patch("app.core.config.settings.floor_plan_prompt_version", "5"):
        step = _new_step()
        got = step._config_hash()
    assert got == _expected_hash(
        background_mode="floor_plan_anchored", prompt_version=V5_PACK
    )


# ----- 2. selector "6" → distinct hash -----


def test_resolved_prompt_version_v6_returns_v6_pack():
    with patch("app.core.config.settings.floor_plan_prompt_version", "6"):
        assert _resolved_prompt_version() == V6_PACK


def test_config_hash_v6_differs_from_default_v5():
    """opt-in v6 만 새로운 hash. v5 default checkpoint 와 같지 않다."""
    with patch("app.core.config.settings.background_mode", "on"), \
         patch("app.core.config.settings.floor_plan_prompt_version", "5"):
        v5_hash = _new_step()._config_hash()
    with patch("app.core.config.settings.background_mode", "on"), \
         patch("app.core.config.settings.floor_plan_prompt_version", "6"):
        v6_hash = _new_step()._config_hash()
    assert v5_hash != v6_hash
    assert v6_hash == _expected_hash(background_mode="on", prompt_version=V6_PACK)


# ----- 3. unknown selector fail-fast -----


def test_resolved_prompt_version_unknown_selector_raises():
    """unknown selector 가 silent latest-pack auto-resolve 로 빠지지 않는다.

    W21B-wave-5: "8" 와 "9" 도 v6-compatible pack 으로 resolve 되므로
    unknown 케이스는 "10" 으로 옮겼고, W21B scale-guideline 에서 "10" 도
    승격되어 이제 "99" 를 쓴다."""
    with patch("app.core.config.settings.floor_plan_prompt_version", "99"):
        with pytest.raises(ValueError, match="unknown floor_plan_prompt selector"):
            _resolved_prompt_version()


def test_config_hash_unknown_selector_raises():
    with patch("app.core.config.settings.background_mode", "on"), \
         patch("app.core.config.settings.floor_plan_prompt_version", "99"):
        step = _new_step()
        with pytest.raises(ValueError):
            step._config_hash()
