"""Tests for ``arautopilot.core.alarms``."""

from __future__ import annotations

import pytest

from arautopilot.core.alarms import (
    Alarm,
    AlarmSeverity,
    AlarmType,
    default_message,
    default_severity,
    triggers_auto_disengage,
)


def test_catalogue_covers_every_alarm_type() -> None:
    """The internal catalogue must define metadata for every enum member."""
    for at in AlarmType:
        # Calling any of the helpers must succeed for every type.
        sev = default_severity(at)
        msg = default_message(at)
        flag = triggers_auto_disengage(at)
        assert isinstance(sev, AlarmSeverity)
        assert isinstance(msg, str) and msg
        assert isinstance(flag, bool)


@pytest.mark.parametrize(
    "alarm_type",
    [
        AlarmType.OFF_COURSE_SEVERE,
        AlarmType.RUDDER_NOT_RESPONDING,
        AlarmType.HEADING_SENSOR_LOST,
        AlarmType.WATCHDOG_TRIPPED,
        AlarmType.VMS_CRITICAL,
        AlarmType.ACTUATOR_OVERCURRENT,
        AlarmType.VOLTAGE_LOW,
    ],
)
def test_safety_critical_alarms_trigger_auto_disengage(alarm_type: AlarmType) -> None:
    """All EMERGENCY alarms (and HIGH overcurrent/voltage) must auto-disengage."""
    assert triggers_auto_disengage(alarm_type) is True


@pytest.mark.parametrize(
    "alarm_type",
    [AlarmType.OFF_COURSE, AlarmType.LIMIT_SWITCH_REACHED],
)
def test_warning_alarms_do_not_disengage(alarm_type: AlarmType) -> None:
    assert triggers_auto_disengage(alarm_type) is False


def test_alarm_from_type_uses_catalogue_defaults() -> None:
    a = Alarm.from_type(AlarmType.OFF_COURSE_SEVERE)
    assert a.type is AlarmType.OFF_COURSE_SEVERE
    assert a.severity is AlarmSeverity.EMERGENCY
    assert a.auto_disengage_triggered is True
    assert a.message  # non-empty
    assert a.source == "firmware"
    assert a.acknowledged is False


def test_alarm_is_frozen() -> None:
    a = Alarm.from_type(AlarmType.OFF_COURSE)
    with pytest.raises((TypeError, ValueError)):
        a.acknowledged = True  # type: ignore[misc]


def test_alarm_rejects_unknown_field() -> None:
    with pytest.raises(ValueError):
        Alarm(
            type=AlarmType.OFF_COURSE,
            severity=AlarmSeverity.LOW,
            message="hi",
            foo="bar",  # type: ignore[call-arg]
        )


def test_alarm_message_length_limits() -> None:
    with pytest.raises(ValueError):
        Alarm(type=AlarmType.OFF_COURSE, severity=AlarmSeverity.LOW, message="")
    with pytest.raises(ValueError):
        Alarm(
            type=AlarmType.OFF_COURSE,
            severity=AlarmSeverity.LOW,
            message="x" * 241,
        )
