"""Area #2 — subject_state helper unit tests (Q2 + Q6 closure)."""
import pytest

from app.core.errors import AppError
from app.core.subject_state import (
    SUBJECT_STATES,
    IMMOBILIZED_STATES,
    SUBJECT_STATE_VISUAL_DESCRIPTOR,
    is_immobilized_state,
    validate_subject_state,
    get_visual_descriptor,
)


class TestSubjectStateConstants:
    def test_subject_states_tuple(self):
        assert SUBJECT_STATES == ("alive", "unconscious", "dead", "severely_injured")

    def test_immobilized_states_frozenset(self):
        assert IMMOBILIZED_STATES == frozenset({"unconscious", "dead", "severely_injured"})
        assert "alive" not in IMMOBILIZED_STATES

    def test_visual_descriptor_keys(self):
        assert set(SUBJECT_STATE_VISUAL_DESCRIPTOR.keys()) == {"dead", "severely_injured", "unconscious"}
        assert "alive" not in SUBJECT_STATE_VISUAL_DESCRIPTOR

    def test_visual_descriptor_non_empty(self):
        for state, desc in SUBJECT_STATE_VISUAL_DESCRIPTOR.items():
            assert isinstance(desc, str) and len(desc) > 10


class TestIsImmobilizedState:
    @pytest.mark.parametrize("state,expected", [
        ("dead", True),
        ("unconscious", True),
        ("severely_injured", True),
        ("alive", False),
        ("invalid_state", False),  # silent False — fixture/우회 silent miss 는 validate_subject_state cover
        ("", False),
        (None, False),
    ])
    def test_is_immobilized_state(self, state, expected):
        assert is_immobilized_state(state) is expected


class TestValidateSubjectState:
    @pytest.mark.parametrize("state", SUBJECT_STATES)
    def test_valid_states_pass(self, state):
        validate_subject_state(state, where="test")  # no raise

    @pytest.mark.parametrize("state", ["invalid", "", "ALIVE", "Dead"])
    def test_invalid_states_fail(self, state):
        with pytest.raises(AppError) as exc_info:
            validate_subject_state(state, where="test.subject_state")
        assert "step.contract_violation.subject_state.enum" in exc_info.value.code


class TestGetVisualDescriptor:
    @pytest.mark.parametrize("state", ["dead", "severely_injured", "unconscious"])
    def test_immobilized_states_return_descriptor(self, state):
        desc = get_visual_descriptor(state)
        assert isinstance(desc, str) and len(desc) > 10

    def test_alive_raises(self):
        with pytest.raises(AppError) as exc_info:
            get_visual_descriptor("alive")
        assert "subject_state.visual_descriptor_not_defined" in exc_info.value.code

    def test_invalid_raises(self):
        with pytest.raises(AppError) as exc_info:
            get_visual_descriptor("invalid")
        assert "subject_state.visual_descriptor_not_defined" in exc_info.value.code
