"""W19B-3 / W20B mutual exclusion guard helper.

background_render w18j_overlap (W19B-3) 와 shot_aware_bg_render_plan
(W20B) 는 동일 reference-graph SOT 를 다르게 산출할 수 있어 둘 다 동시에
활성화되면 silent divergence — 어느 path 의 결과가 downstream consumer
에 반영될지 운영자가 알아채지 못한다.  fail-closed 로 차단.

contract:
    conflict := (
        settings.background_render_reference_mode == "w18j_overlap"
        and bool(settings.shot_aware_bg_render_plan_enabled)
    )

caller side (background_render_step._execute / shot_aware_bg_render_plan_step._execute)
는 정상 applicability gate 통과 후 ‑ 외부 호출 / DB / ImageAsset write 전 ‑ 에
``detect_w19b3_w20b_conflict()`` 를 호출, 반환값이 None 이 아니면 step result
를 ``failed_count=1 + diagnostic`` 형태로 emit (not_applicable 아님 — operator
가 두 selector 가 동시에 켜진 상태를 즉시 감지하도록).
"""
from __future__ import annotations

from typing import Any, Optional


def detect_w19b3_w20b_conflict(settings: Any) -> Optional[str]:
    """W19B-3 / W20B 가 동시에 활성화돼 있으면 diagnostic 문자열, 아니면 None.

    한쪽만 활성이거나 둘 다 default off 일 때는 None.  caller 가 이 결과를
    그대로 step result error / diagnostic field 에 실어 fail-closed 처리.
    """
    if (
        getattr(settings, "background_render_reference_mode", "legacy")
        == "w18j_overlap"
        and bool(getattr(settings, "shot_aware_bg_render_plan_enabled", False))
    ):
        return (
            "W19B-3/W20B selector conflict: "
            "background_render_reference_mode='w18j_overlap' AND "
            "shot_aware_bg_render_plan_enabled=True are mutually exclusive. "
            "exactly one of the two reference-graph paths may be opt-in at a time."
        )
    return None
