"""Tests for siren platform."""

from kasa import Device, Module
import pytest
from syrupy.assertion import SnapshotAssertion

from homeassistant.components.siren import (
    ATTR_DURATION,
    ATTR_TONE,
    ATTR_VOLUME_LEVEL,
    DOMAIN as SIREN_DOMAIN,
    SERVICE_TURN_OFF,
    SERVICE_TURN_ON,
)
from homeassistant.const import ATTR_ENTITY_ID, Platform
from homeassistant.core import HomeAssistant
from homeassistant.exceptions import ServiceValidationError
from homeassistant.helpers import device_registry as dr, entity_registry as er

from . import _mocked_device, setup_platform_for_device, snapshot_platform

from tests.common import MockConfigEntry

ENTITY_ID = "siren.hub"


@pytest.fixture
async def mocked_hub(hass: HomeAssistant) -> Device:
    """Return mocked tplink hub with an alarm module."""

    return _mocked_device(
        alias="hub",
        modules=[Module.Alarm],
        device_type=Device.Type.Hub,
    )


async def test_states(
    hass: HomeAssistant,
    mock_config_entry: MockConfigEntry,
    entity_registry: er.EntityRegistry,
    device_registry: dr.DeviceRegistry,
    snapshot: SnapshotAssertion,
    mocked_hub: Device,
) -> None:
    """Snapshot test."""
    await setup_platform_for_device(hass, mock_config_entry, Platform.SIREN, mocked_hub)

    await snapshot_platform(
        hass, entity_registry, device_registry, snapshot, mock_config_entry.entry_id
    )


async def test_turn_on_and_off(
    hass: HomeAssistant, mock_config_entry: MockConfigEntry, mocked_hub: Device
) -> None:
    """Test that turn_on and turn_off services work as expected."""
    await setup_platform_for_device(hass, mock_config_entry, Platform.SIREN, mocked_hub)

    alarm_module = mocked_hub.modules[Module.Alarm]

    await hass.services.async_call(
        SIREN_DOMAIN,
        SERVICE_TURN_OFF,
        {ATTR_ENTITY_ID: [ENTITY_ID]},
        blocking=True,
    )

    alarm_module.stop.assert_called()

    await hass.services.async_call(
        SIREN_DOMAIN,
        SERVICE_TURN_ON,
        {ATTR_ENTITY_ID: [ENTITY_ID]},
        blocking=True,
    )

    alarm_module.play.assert_called()


@pytest.mark.parametrize(
    ("max_volume", "volume_level", "expected_volume"),
    [
        pytest.param(3, 0.1, 1, id="smart-10%"),
        pytest.param(3, 0.3, 1, id="smart-30%"),
        pytest.param(3, 0.99, 3, id="smart-99%"),
        pytest.param(3, 1, 3, id="smart-100%"),
        pytest.param(10, 0.1, 1, id="smartcam-10%"),
        pytest.param(10, 0.3, 3, id="smartcam-30%"),
        pytest.param(10, 0.99, 10, id="smartcam-99%"),
        pytest.param(10, 1, 10, id="smartcam-100%"),
    ],
)
async def test_turn_on_with_volume(
    hass: HomeAssistant,
    mock_config_entry: MockConfigEntry,
    mocked_hub: Device,
    max_volume: int,
    volume_level: float,
    expected_volume: int,
) -> None:
    """Test that turn_on volume parameters work as expected."""

    alarm_module = mocked_hub.modules[Module.Alarm]
    alarm_volume_feat = alarm_module.get_feature("alarm_volume")
    assert alarm_volume_feat
    alarm_volume_feat.maximum_value = max_volume

    await setup_platform_for_device(hass, mock_config_entry, Platform.SIREN, mocked_hub)

    await hass.services.async_call(
        SIREN_DOMAIN,
        SERVICE_TURN_ON,
        {ATTR_ENTITY_ID: [ENTITY_ID], ATTR_VOLUME_LEVEL: volume_level},
        blocking=True,
    )

    alarm_module.play.assert_called_with(
        volume=expected_volume, duration=None, sound=None
    )


async def test_turn_on_with_duration_and_sound(
    hass: HomeAssistant,
    mock_config_entry: MockConfigEntry,
    mocked_hub: Device,
) -> None:
    """Test that turn_on tone and duration parameters work as expected."""

    alarm_module = mocked_hub.modules[Module.Alarm]

    await setup_platform_for_device(hass, mock_config_entry, Platform.SIREN, mocked_hub)

    await hass.services.async_call(
        SIREN_DOMAIN,
        SERVICE_TURN_ON,
        {ATTR_ENTITY_ID: [ENTITY_ID], ATTR_DURATION: 5, ATTR_TONE: "Foo"},
        blocking=True,
    )

    alarm_module.play.assert_called_with(volume=None, duration=5, sound="Foo")


@pytest.mark.parametrize(("duration"), [0, 301])
async def test_turn_on_with_invalid_duration(
    hass: HomeAssistant,
    mock_config_entry: MockConfigEntry,
    mocked_hub: Device,
    duration: int,
) -> None:
    """Test that turn_on with invalid_duration raises an error."""

    await setup_platform_for_device(hass, mock_config_entry, Platform.SIREN, mocked_hub)

    msg = f"Invalid duration {duration} available: 1-300s"

    with pytest.raises(ServiceValidationError, match=msg):
        await hass.services.async_call(
            SIREN_DOMAIN,
            SERVICE_TURN_ON,
            {
                ATTR_ENTITY_ID: [ENTITY_ID],
                ATTR_DURATION: duration,
            },
            blocking=True,
        )
