"""Area #3 W3 — detect_offscreen_drift_proximity_diagnostic Path 2 unit tests.

Path 2 = camera_direction OFFSCREEN_RE gate + proximity NL fallback.
Diagnostic only (no raise). character_angles (optional) for in_frame_guarantee.
"""
import pytest

from app.modules.pipeline.shot_visibility import (
    detect_offscreen_drift_proximity_diagnostic,
)


class TestProximityNLFallback:
    def test_proximity_match_returns_drift_candidate(self):
        """OFFSCREEN_RE 매치 + proximity 윈도우 안 character name → candidate."""
        result = detect_offscreen_drift_proximity_diagnostic(
            visible_ids=["C01"],
            camera_direction="캐릭터A is off-camera in this shot.",
            id_to_name={"C01": "캐릭터A"},
        )
        # 캐릭터A 는 visible 안에 있지만 offscreen phrase 인접 → drift candidate
        assert result == {"C01": "캐릭터A"}, (
            "proximity NL: offscreen phrase 직전 윈도우 안 character name → drift"
        )


class TestInFrameGuaranteeOptional:
    def test_in_frame_excludes_proximity_candidate(self):
        """character_angles[].character == visible name → drift 후보 제외."""
        result = detect_offscreen_drift_proximity_diagnostic(
            visible_ids=["C01"],
            camera_direction="캐릭터A is off-camera in this shot.",
            id_to_name={"C01": "캐릭터A"},
            character_angles=[{"character": "캐릭터A"}],  # in-frame guarantee
        )
        assert result == {}, "in_frame_guarantee: proximity candidate 제외"


class TestEmptyInputs:
    def test_empty_camera_direction(self):
        result = detect_offscreen_drift_proximity_diagnostic(
            visible_ids=["C01"],
            camera_direction="",
            id_to_name={"C01": "캐릭터A"},
        )
        assert result == {}

    def test_no_offscreen_phrase(self):
        result = detect_offscreen_drift_proximity_diagnostic(
            visible_ids=["C01"],
            camera_direction="standard mid-shot",
            id_to_name={"C01": "캐릭터A"},
        )
        assert result == {}
