"""Test the UniFi Protect select platform."""
# pylint: disable=protected-access
from __future__ import annotations

from copy import copy
from datetime import timedelta
from unittest.mock import AsyncMock, Mock, patch

import pytest
from pyunifiprotect.data import Camera, Light
from pyunifiprotect.data.devices import LCDMessage, Viewer
from pyunifiprotect.data.nvr import DoorbellMessage, Liveview
from pyunifiprotect.data.types import (
    DoorbellMessageType,
    IRLEDMode,
    LightModeEnableType,
    LightModeType,
    RecordingMode,
)

from homeassistant.components.select.const import ATTR_OPTIONS
from homeassistant.components.unifiprotect.const import (
    ATTR_DURATION,
    ATTR_MESSAGE,
    DEFAULT_ATTRIBUTION,
)
from homeassistant.components.unifiprotect.select import (
    CAMERA_SELECTS,
    LIGHT_MODE_OFF,
    LIGHT_SELECTS,
    SERVICE_SET_DOORBELL_MESSAGE,
    VIEWER_SELECTS,
)
from homeassistant.const import ATTR_ATTRIBUTION, ATTR_ENTITY_ID, ATTR_OPTION, Platform
from homeassistant.core import HomeAssistant
from homeassistant.exceptions import HomeAssistantError
from homeassistant.helpers import entity_registry as er
from homeassistant.util.dt import utcnow

from .conftest import (
    MockEntityFixture,
    assert_entity_counts,
    ids_from_device_description,
)


@pytest.fixture(name="viewer")
async def viewer_fixture(
    hass: HomeAssistant,
    mock_entry: MockEntityFixture,
    mock_viewer: Viewer,
    mock_liveview: Liveview,
):
    """Fixture for a single viewport for testing the select platform."""

    # disable pydantic validation so mocking can happen
    Viewer.__config__.validate_assignment = False

    viewer_obj = mock_viewer.copy(deep=True)
    viewer_obj._api = mock_entry.api
    viewer_obj.name = "Test Viewer"
    viewer_obj.liveview_id = mock_liveview.id

    mock_entry.api.bootstrap.reset_objects()
    mock_entry.api.bootstrap.viewers = {
        viewer_obj.id: viewer_obj,
    }
    mock_entry.api.bootstrap.liveviews = {mock_liveview.id: mock_liveview}

    await hass.config_entries.async_setup(mock_entry.entry.entry_id)
    await hass.async_block_till_done()

    assert_entity_counts(hass, Platform.SELECT, 1, 1)

    yield viewer_obj

    Viewer.__config__.validate_assignment = True


@pytest.fixture(name="camera")
async def camera_fixture(
    hass: HomeAssistant, mock_entry: MockEntityFixture, mock_camera: Camera
):
    """Fixture for a single camera for testing the select platform."""

    # disable pydantic validation so mocking can happen
    Camera.__config__.validate_assignment = False

    camera_obj = mock_camera.copy(deep=True)
    camera_obj._api = mock_entry.api
    camera_obj.channels[0]._api = mock_entry.api
    camera_obj.channels[1]._api = mock_entry.api
    camera_obj.channels[2]._api = mock_entry.api
    camera_obj.name = "Test Camera"
    camera_obj.feature_flags.has_lcd_screen = True
    camera_obj.feature_flags.has_chime = True
    camera_obj.recording_settings.mode = RecordingMode.ALWAYS
    camera_obj.isp_settings.ir_led_mode = IRLEDMode.AUTO
    camera_obj.lcd_message = None
    camera_obj.chime_duration = 0

    mock_entry.api.bootstrap.reset_objects()
    mock_entry.api.bootstrap.cameras = {
        camera_obj.id: camera_obj,
    }

    await hass.config_entries.async_setup(mock_entry.entry.entry_id)
    await hass.async_block_till_done()

    assert_entity_counts(hass, Platform.SELECT, 4, 4)

    yield camera_obj

    Camera.__config__.validate_assignment = True


@pytest.fixture(name="light")
async def light_fixture(
    hass: HomeAssistant,
    mock_entry: MockEntityFixture,
    mock_light: Light,
    camera: Camera,
):
    """Fixture for a single light for testing the select platform."""

    # disable pydantic validation so mocking can happen
    Light.__config__.validate_assignment = False

    light_obj = mock_light.copy(deep=True)
    light_obj._api = mock_entry.api
    light_obj.name = "Test Light"
    light_obj.camera_id = None
    light_obj.light_mode_settings.mode = LightModeType.MOTION
    light_obj.light_mode_settings.enable_at = LightModeEnableType.DARK

    mock_entry.api.bootstrap.reset_objects()
    mock_entry.api.bootstrap.cameras = {camera.id: camera}
    mock_entry.api.bootstrap.lights = {
        light_obj.id: light_obj,
    }

    await hass.config_entries.async_reload(mock_entry.entry.entry_id)
    await hass.async_block_till_done()

    assert_entity_counts(hass, Platform.SELECT, 6, 6)

    yield light_obj

    Light.__config__.validate_assignment = True


@pytest.fixture(name="camera_none")
async def camera_none_fixture(
    hass: HomeAssistant, mock_entry: MockEntityFixture, mock_camera: Camera
):
    """Fixture for a single camera for testing the select platform."""

    # disable pydantic validation so mocking can happen
    Camera.__config__.validate_assignment = False

    camera_obj = mock_camera.copy(deep=True)
    camera_obj._api = mock_entry.api
    camera_obj.channels[0]._api = mock_entry.api
    camera_obj.channels[1]._api = mock_entry.api
    camera_obj.channels[2]._api = mock_entry.api
    camera_obj.name = "Test Camera"
    camera_obj.feature_flags.has_lcd_screen = False
    camera_obj.feature_flags.has_chime = False
    camera_obj.recording_settings.mode = RecordingMode.ALWAYS
    camera_obj.isp_settings.ir_led_mode = IRLEDMode.AUTO

    mock_entry.api.bootstrap.reset_objects()
    mock_entry.api.bootstrap.cameras = {
        camera_obj.id: camera_obj,
    }

    await hass.config_entries.async_setup(mock_entry.entry.entry_id)
    await hass.async_block_till_done()

    assert_entity_counts(hass, Platform.SELECT, 2, 2)

    yield camera_obj

    Camera.__config__.validate_assignment = True


async def test_select_setup_light(
    hass: HomeAssistant,
    light: Light,
):
    """Test select entity setup for light devices."""

    entity_registry = er.async_get(hass)
    expected_values = ("On Motion - When Dark", "Not Paired")

    for index, description in enumerate(LIGHT_SELECTS):
        unique_id, entity_id = ids_from_device_description(
            Platform.SELECT, light, description
        )

        entity = entity_registry.async_get(entity_id)
        assert entity
        assert entity.unique_id == unique_id

        state = hass.states.get(entity_id)
        assert state
        assert state.state == expected_values[index]
        assert state.attributes[ATTR_ATTRIBUTION] == DEFAULT_ATTRIBUTION


async def test_select_setup_viewer(
    hass: HomeAssistant,
    viewer: Viewer,
):
    """Test select entity setup for light devices."""

    entity_registry = er.async_get(hass)
    description = VIEWER_SELECTS[0]

    unique_id, entity_id = ids_from_device_description(
        Platform.SELECT, viewer, description
    )

    entity = entity_registry.async_get(entity_id)
    assert entity
    assert entity.unique_id == unique_id

    state = hass.states.get(entity_id)
    assert state
    assert state.state == viewer.liveview.name
    assert state.attributes[ATTR_ATTRIBUTION] == DEFAULT_ATTRIBUTION


async def test_select_setup_camera_all(
    hass: HomeAssistant,
    camera: Camera,
):
    """Test select entity setup for camera devices (all features)."""

    entity_registry = er.async_get(hass)
    expected_values = ("Always", "Auto", "Default Message (Welcome)", "None")

    for index, description in enumerate(CAMERA_SELECTS):
        unique_id, entity_id = ids_from_device_description(
            Platform.SELECT, camera, description
        )

        entity = entity_registry.async_get(entity_id)
        assert entity
        assert entity.unique_id == unique_id

        state = hass.states.get(entity_id)
        assert state
        assert state.state == expected_values[index]
        assert state.attributes[ATTR_ATTRIBUTION] == DEFAULT_ATTRIBUTION


async def test_select_setup_camera_none(
    hass: HomeAssistant,
    camera_none: Camera,
):
    """Test select entity setup for camera devices (no features)."""

    entity_registry = er.async_get(hass)
    expected_values = ("Always", "Auto", "Default Message (Welcome)")

    for index, description in enumerate(CAMERA_SELECTS):
        if index == 2:
            return

        unique_id, entity_id = ids_from_device_description(
            Platform.SELECT, camera_none, description
        )

        entity = entity_registry.async_get(entity_id)
        assert entity
        assert entity.unique_id == unique_id

        state = hass.states.get(entity_id)
        assert state
        assert state.state == expected_values[index]
        assert state.attributes[ATTR_ATTRIBUTION] == DEFAULT_ATTRIBUTION


async def test_select_update_liveview(
    hass: HomeAssistant,
    mock_entry: MockEntityFixture,
    viewer: Viewer,
    mock_liveview: Liveview,
):
    """Test select entity update (new Liveview)."""

    _, entity_id = ids_from_device_description(
        Platform.SELECT, viewer, VIEWER_SELECTS[0]
    )

    state = hass.states.get(entity_id)
    assert state
    expected_options = state.attributes[ATTR_OPTIONS]

    new_bootstrap = copy(mock_entry.api.bootstrap)
    new_liveview = copy(mock_liveview)
    new_liveview.id = "test_id"

    mock_msg = Mock()
    mock_msg.changed_data = {}
    mock_msg.new_obj = new_liveview

    new_bootstrap.liveviews = {**new_bootstrap.liveviews, new_liveview.id: new_liveview}
    mock_entry.api.bootstrap = new_bootstrap
    mock_entry.api.ws_subscription(mock_msg)
    await hass.async_block_till_done()

    state = hass.states.get(entity_id)
    assert state
    assert state.attributes[ATTR_OPTIONS] == expected_options


async def test_select_update_doorbell_settings(
    hass: HomeAssistant, mock_entry: MockEntityFixture, camera: Camera
):
    """Test select entity update (new Doorbell Message)."""

    expected_length = (
        len(mock_entry.api.bootstrap.nvr.doorbell_settings.all_messages) + 1
    )

    _, entity_id = ids_from_device_description(
        Platform.SELECT, camera, CAMERA_SELECTS[2]
    )

    state = hass.states.get(entity_id)
    assert state
    assert len(state.attributes[ATTR_OPTIONS]) == expected_length

    expected_length += 1
    new_nvr = copy(mock_entry.api.bootstrap.nvr)
    new_nvr.__fields__["update_all_messages"] = Mock()
    new_nvr.update_all_messages = Mock()

    new_nvr.doorbell_settings.all_messages = [
        *new_nvr.doorbell_settings.all_messages,
        DoorbellMessage(
            type=DoorbellMessageType.CUSTOM_MESSAGE,
            text="Test2",
        ),
    ]

    mock_msg = Mock()
    mock_msg.changed_data = {"doorbell_settings": {}}
    mock_msg.new_obj = new_nvr

    mock_entry.api.bootstrap.nvr = new_nvr
    mock_entry.api.ws_subscription(mock_msg)
    await hass.async_block_till_done()

    new_nvr.update_all_messages.assert_called_once()

    state = hass.states.get(entity_id)
    assert state
    assert len(state.attributes[ATTR_OPTIONS]) == expected_length


async def test_select_update_doorbell_message(
    hass: HomeAssistant,
    mock_entry: MockEntityFixture,
    camera: Camera,
):
    """Test select entity update (change doorbell message)."""

    _, entity_id = ids_from_device_description(
        Platform.SELECT, camera, CAMERA_SELECTS[2]
    )

    state = hass.states.get(entity_id)
    assert state
    assert state.state == "Default Message (Welcome)"

    new_bootstrap = copy(mock_entry.api.bootstrap)
    new_camera = camera.copy()
    new_camera.lcd_message = LCDMessage(
        type=DoorbellMessageType.CUSTOM_MESSAGE, text="Test"
    )

    mock_msg = Mock()
    mock_msg.changed_data = {}
    mock_msg.new_obj = new_camera

    new_bootstrap.cameras = {new_camera.id: new_camera}
    mock_entry.api.bootstrap = new_bootstrap
    mock_entry.api.ws_subscription(mock_msg)
    await hass.async_block_till_done()

    state = hass.states.get(entity_id)
    assert state
    assert state.state == "Test"


async def test_select_set_option_light_motion(
    hass: HomeAssistant,
    light: Light,
):
    """Test Light Mode select."""
    _, entity_id = ids_from_device_description(Platform.SELECT, light, LIGHT_SELECTS[0])

    light.__fields__["set_light_settings"] = Mock()
    light.set_light_settings = AsyncMock()

    await hass.services.async_call(
        "select",
        "select_option",
        {ATTR_ENTITY_ID: entity_id, ATTR_OPTION: LIGHT_MODE_OFF},
        blocking=True,
    )

    light.set_light_settings.assert_called_once_with(
        LightModeType.MANUAL, enable_at=None
    )


async def test_select_set_option_light_camera(
    hass: HomeAssistant,
    light: Light,
):
    """Test Paired Camera select."""
    _, entity_id = ids_from_device_description(Platform.SELECT, light, LIGHT_SELECTS[1])

    light.__fields__["set_paired_camera"] = Mock()
    light.set_paired_camera = AsyncMock()

    camera = list(light.api.bootstrap.cameras.values())[0]

    await hass.services.async_call(
        "select",
        "select_option",
        {ATTR_ENTITY_ID: entity_id, ATTR_OPTION: camera.name},
        blocking=True,
    )

    light.set_paired_camera.assert_called_once_with(camera)

    await hass.services.async_call(
        "select",
        "select_option",
        {ATTR_ENTITY_ID: entity_id, ATTR_OPTION: "Not Paired"},
        blocking=True,
    )

    light.set_paired_camera.assert_called_with(None)


async def test_select_set_option_camera_recording(
    hass: HomeAssistant,
    camera: Camera,
):
    """Test Recording Mode select."""
    _, entity_id = ids_from_device_description(
        Platform.SELECT, camera, CAMERA_SELECTS[0]
    )

    camera.__fields__["set_recording_mode"] = Mock()
    camera.set_recording_mode = AsyncMock()

    await hass.services.async_call(
        "select",
        "select_option",
        {ATTR_ENTITY_ID: entity_id, ATTR_OPTION: "Never"},
        blocking=True,
    )

    camera.set_recording_mode.assert_called_once_with(RecordingMode.NEVER)


async def test_select_set_option_camera_ir(
    hass: HomeAssistant,
    camera: Camera,
):
    """Test Infrared Mode select."""
    _, entity_id = ids_from_device_description(
        Platform.SELECT, camera, CAMERA_SELECTS[1]
    )

    camera.__fields__["set_ir_led_model"] = Mock()
    camera.set_ir_led_model = AsyncMock()

    await hass.services.async_call(
        "select",
        "select_option",
        {ATTR_ENTITY_ID: entity_id, ATTR_OPTION: "Always Enable"},
        blocking=True,
    )

    camera.set_ir_led_model.assert_called_once_with(IRLEDMode.ON)


async def test_select_set_option_camera_doorbell_custom(
    hass: HomeAssistant,
    camera: Camera,
):
    """Test Doorbell Text select (user defined message)."""
    _, entity_id = ids_from_device_description(
        Platform.SELECT, camera, CAMERA_SELECTS[2]
    )

    camera.__fields__["set_lcd_text"] = Mock()
    camera.set_lcd_text = AsyncMock()

    await hass.services.async_call(
        "select",
        "select_option",
        {ATTR_ENTITY_ID: entity_id, ATTR_OPTION: "Test"},
        blocking=True,
    )

    camera.set_lcd_text.assert_called_once_with(
        DoorbellMessageType.CUSTOM_MESSAGE, text="Test"
    )


async def test_select_set_option_camera_doorbell_unifi(
    hass: HomeAssistant,
    camera: Camera,
):
    """Test Doorbell Text select (unifi message)."""
    _, entity_id = ids_from_device_description(
        Platform.SELECT, camera, CAMERA_SELECTS[2]
    )

    camera.__fields__["set_lcd_text"] = Mock()
    camera.set_lcd_text = AsyncMock()

    await hass.services.async_call(
        "select",
        "select_option",
        {
            ATTR_ENTITY_ID: entity_id,
            ATTR_OPTION: "LEAVE PACKAGE AT DOOR",
        },
        blocking=True,
    )

    camera.set_lcd_text.assert_called_once_with(
        DoorbellMessageType.LEAVE_PACKAGE_AT_DOOR
    )

    await hass.services.async_call(
        "select",
        "select_option",
        {
            ATTR_ENTITY_ID: entity_id,
            ATTR_OPTION: "Default Message (Welcome)",
        },
        blocking=True,
    )

    camera.set_lcd_text.assert_called_with(None)


async def test_select_set_option_camera_doorbell_default(
    hass: HomeAssistant,
    camera: Camera,
):
    """Test Doorbell Text select (default message)."""
    _, entity_id = ids_from_device_description(
        Platform.SELECT, camera, CAMERA_SELECTS[2]
    )

    camera.__fields__["set_lcd_text"] = Mock()
    camera.set_lcd_text = AsyncMock()

    await hass.services.async_call(
        "select",
        "select_option",
        {
            ATTR_ENTITY_ID: entity_id,
            ATTR_OPTION: "Default Message (Welcome)",
        },
        blocking=True,
    )

    camera.set_lcd_text.assert_called_once_with(None)


async def test_select_set_option_viewer(
    hass: HomeAssistant,
    viewer: Viewer,
):
    """Test Liveview select."""
    _, entity_id = ids_from_device_description(
        Platform.SELECT, viewer, VIEWER_SELECTS[0]
    )

    viewer.__fields__["set_liveview"] = Mock()
    viewer.set_liveview = AsyncMock()

    liveview = list(viewer.api.bootstrap.liveviews.values())[0]

    await hass.services.async_call(
        "select",
        "select_option",
        {ATTR_ENTITY_ID: entity_id, ATTR_OPTION: liveview.name},
        blocking=True,
    )

    viewer.set_liveview.assert_called_once_with(liveview)


async def test_select_service_doorbell_invalid(
    hass: HomeAssistant,
    camera: Camera,
):
    """Test Doorbell Text service (invalid)."""
    _, entity_id = ids_from_device_description(
        Platform.SELECT, camera, CAMERA_SELECTS[1]
    )

    camera.__fields__["set_lcd_text"] = Mock()
    camera.set_lcd_text = AsyncMock()

    with pytest.raises(HomeAssistantError):
        await hass.services.async_call(
            "unifiprotect",
            SERVICE_SET_DOORBELL_MESSAGE,
            {ATTR_ENTITY_ID: entity_id, ATTR_MESSAGE: "Test"},
            blocking=True,
        )

    assert not camera.set_lcd_text.called


async def test_select_service_doorbell_success(
    hass: HomeAssistant,
    camera: Camera,
):
    """Test Doorbell Text service (success)."""
    _, entity_id = ids_from_device_description(
        Platform.SELECT, camera, CAMERA_SELECTS[2]
    )

    camera.__fields__["set_lcd_text"] = Mock()
    camera.set_lcd_text = AsyncMock()

    await hass.services.async_call(
        "unifiprotect",
        SERVICE_SET_DOORBELL_MESSAGE,
        {
            ATTR_ENTITY_ID: entity_id,
            ATTR_MESSAGE: "Test",
        },
        blocking=True,
    )

    camera.set_lcd_text.assert_called_once_with(
        DoorbellMessageType.CUSTOM_MESSAGE, "Test", reset_at=None
    )


@patch("homeassistant.components.unifiprotect.select.utcnow")
async def test_select_service_doorbell_with_reset(
    mock_now,
    hass: HomeAssistant,
    camera: Camera,
):
    """Test Doorbell Text service (success with reset time)."""
    now = utcnow()
    mock_now.return_value = now

    _, entity_id = ids_from_device_description(
        Platform.SELECT, camera, CAMERA_SELECTS[2]
    )

    camera.__fields__["set_lcd_text"] = Mock()
    camera.set_lcd_text = AsyncMock()

    await hass.services.async_call(
        "unifiprotect",
        SERVICE_SET_DOORBELL_MESSAGE,
        {
            ATTR_ENTITY_ID: entity_id,
            ATTR_MESSAGE: "Test",
            ATTR_DURATION: 60,
        },
        blocking=True,
    )

    camera.set_lcd_text.assert_called_once_with(
        DoorbellMessageType.CUSTOM_MESSAGE,
        "Test",
        reset_at=now + timedelta(minutes=60),
    )

35b1d0fdceac008dfd7e965d52c12fcf906f6944
<mask token>

<mask token>


@pytest.fixture(name='viewer')
async def viewer_fixture(hass: HomeAssistant, mock_entry: MockEntityFixture,
    mock_viewer: Viewer, mock_liveview: Liveview):
    """Fixture for a single viewport for testing the select platform."""
    Viewer.__config__.validate_assignment = False
    viewer_obj = mock_viewer.copy(deep=True)
    viewer_obj._api = mock_entry.api
    viewer_obj.name = 'Test Viewer'
    viewer_obj.liveview_id = mock_liveview.id
    mock_entry.api.bootstrap.reset_objects()
    mock_entry.api.bootstrap.viewers = {viewer_obj.id: viewer_obj}
    mock_entry.api.bootstrap.liveviews = {mock_liveview.id: mock_liveview}
    await hass.config_entries.async_setup(mock_entry.entry.entry_id)
    await hass.async_block_till_done()
    assert_entity_counts(hass, Platform.SELECT, 1, 1)
    yield viewer_obj
    Viewer.__config__.validate_assignment = True


@pytest.fixture(name='camera')
async def camera_fixture(hass: HomeAssistant, mock_entry: MockEntityFixture,
    mock_camera: Camera):
    """Fixture for a single camera for testing the select platform."""
    Camera.__config__.validate_assignment = False
    camera_obj = mock_camera.copy(deep=True)
    camera_obj._api = mock_entry.api
    camera_obj.channels[0]._api = mock_entry.api
    camera_obj.channels[1]._api = mock_entry.api
    camera_obj.channels[2]._api = mock_entry.api
    camera_obj.name = 'Test Camera'
    camera_obj.feature_flags.has_lcd_screen = True
    camera_obj.feature_flags.has_chime = True
    camera_obj.recording_settings.mode = RecordingMode.ALWAYS
    camera_obj.isp_settings.ir_led_mode = IRLEDMode.AUTO
    camera_obj.lcd_message = None
    camera_obj.chime_duration = 0
    mock_entry.api.bootstrap.reset_objects()
    mock_entry.api.bootstrap.cameras = {camera_obj.id: camera_obj}
    await hass.config_entries.async_setup(mock_entry.entry.entry_id)
    await hass.async_block_till_done()
    assert_entity_counts(hass, Platform.SELECT, 4, 4)
    yield camera_obj
    Camera.__config__.validate_assignment = True


@pytest.fixture(name='light')
async def light_fixture(hass: HomeAssistant, mock_entry: MockEntityFixture,
    mock_light: Light, camera: Camera):
    """Fixture for a single light for testing the select platform."""
    Light.__config__.validate_assignment = False
    light_obj = mock_light.copy(deep=True)
    light_obj._api = mock_entry.api
    light_obj.name = 'Test Light'
    light_obj.camera_id = None
    light_obj.light_mode_settings.mode = LightModeType.MOTION
    light_obj.light_mode_settings.enable_at = LightModeEnableType.DARK
    mock_entry.api.bootstrap.reset_objects()
    mock_entry.api.bootstrap.cameras = {camera.id: camera}
    mock_entry.api.bootstrap.lights = {light_obj.id: light_obj}
    await hass.config_entries.async_reload(mock_entry.entry.entry_id)
    await hass.async_block_till_done()
    assert_entity_counts(hass, Platform.SELECT, 6, 6)
    yield light_obj
    Light.__config__.validate_assignment = True


@pytest.fixture(name='camera_none')
async def camera_none_fixture(hass: HomeAssistant, mock_entry:
    MockEntityFixture, mock_camera: Camera):
    """Fixture for a single camera for testing the select platform."""
    Camera.__config__.validate_assignment = False
    camera_obj = mock_camera.copy(deep=True)
    camera_obj._api = mock_entry.api
    camera_obj.channels[0]._api = mock_entry.api
    camera_obj.channels[1]._api = mock_entry.api
    camera_obj.channels[2]._api = mock_entry.api
    camera_obj.name = 'Test Camera'
    camera_obj.feature_flags.has_lcd_screen = False
    camera_obj.feature_flags.has_chime = False
    camera_obj.recording_settings.mode = RecordingMode.ALWAYS
    camera_obj.isp_settings.ir_led_mode = IRLEDMode.AUTO
    mock_entry.api.bootstrap.reset_objects()
    mock_entry.api.bootstrap.cameras = {camera_obj.id: camera_obj}
    await hass.config_entries.async_setup(mock_entry.entry.entry_id)
    await hass.async_block_till_done()
    assert_entity_counts(hass, Platform.SELECT, 2, 2)
    yield camera_obj
    Camera.__config__.validate_assignment = True


async def test_select_setup_light(hass: HomeAssistant, light: Light):
    """Test select entity setup for light devices."""
    entity_registry = er.async_get(hass)
    expected_values = 'On Motion - When Dark', 'Not Paired'
    for index, description in enumerate(LIGHT_SELECTS):
        unique_id, entity_id = ids_from_device_description(Platform.SELECT,
            light, description)
        entity = entity_registry.async_get(entity_id)
        assert entity
        assert entity.unique_id == unique_id
        state = hass.states.get(entity_id)
        assert state
        assert state.state == expected_values[index]
        assert state.attributes[ATTR_ATTRIBUTION] == DEFAULT_ATTRIBUTION


async def test_select_setup_viewer(hass: HomeAssistant, viewer: Viewer):
    """Test select entity setup for light devices."""
    entity_registry = er.async_get(hass)
    description = VIEWER_SELECTS[0]
    unique_id, entity_id = ids_from_device_description(Platform.SELECT,
        viewer, description)
    entity = entity_registry.async_get(entity_id)
    assert entity
    assert entity.unique_id == unique_id
    state = hass.states.get(entity_id)
    assert state
    assert state.state == viewer.liveview.name
    assert state.attributes[ATTR_ATTRIBUTION] == DEFAULT_ATTRIBUTION


async def test_select_setup_camera_all(hass: HomeAssistant, camera: Camera):
    """Test select entity setup for camera devices (all features)."""
    entity_registry = er.async_get(hass)
    expected_values = 'Always', 'Auto', 'Default Message (Welcome)', 'None'
    for index, description in enumerate(CAMERA_SELECTS):
        unique_id, entity_id = ids_from_device_description(Platform.SELECT,
            camera, description)
        entity = entity_registry.async_get(entity_id)
        assert entity
        assert entity.unique_id == unique_id
        state = hass.states.get(entity_id)
        assert state
        assert state.state == expected_values[index]
        assert state.attributes[ATTR_ATTRIBUTION] == DEFAULT_ATTRIBUTION


async def test_select_setup_camera_none(hass: HomeAssistant, camera_none:
    Camera):
    """Test select entity setup for camera devices (no features)."""
    entity_registry = er.async_get(hass)
    expected_values = 'Always', 'Auto', 'Default Message (Welcome)'
    for index, description in enumerate(CAMERA_SELECTS):
        if index == 2:
            return
        unique_id, entity_id = ids_from_device_description(Platform.SELECT,
            camera_none, description)
        entity = entity_registry.async_get(entity_id)
        assert entity
        assert entity.unique_id == unique_id
        state = hass.states.get(entity_id)
        assert state
        assert state.state == expected_values[index]
        assert state.attributes[ATTR_ATTRIBUTION] == DEFAULT_ATTRIBUTION


async def test_select_update_liveview(hass: HomeAssistant, mock_entry:
    MockEntityFixture, viewer: Viewer, mock_liveview: Liveview):
    """Test select entity update (new Liveview)."""
    _, entity_id = ids_from_device_description(Platform.SELECT, viewer,
        VIEWER_SELECTS[0])
    state = hass.states.get(entity_id)
    assert state
    expected_options = state.attributes[ATTR_OPTIONS]
    new_bootstrap = copy(mock_entry.api.bootstrap)
    new_liveview = copy(mock_liveview)
    new_liveview.id = 'test_id'
    mock_msg = Mock()
    mock_msg.changed_data = {}
    mock_msg.new_obj = new_liveview
    new_bootstrap.liveviews = {**new_bootstrap.liveviews, new_liveview.id:
        new_liveview}
    mock_entry.api.bootstrap = new_bootstrap
    mock_entry.api.ws_subscription(mock_msg)
    await hass.async_block_till_done()
    state = hass.states.get(entity_id)
    assert state
    assert state.attributes[ATTR_OPTIONS] == expected_options


async def test_select_update_doorbell_settings(hass: HomeAssistant,
    mock_entry: MockEntityFixture, camera: Camera):
    """Test select entity update (new Doorbell Message)."""
    expected_length = len(mock_entry.api.bootstrap.nvr.doorbell_settings.
        all_messages) + 1
    _, entity_id = ids_from_device_description(Platform.SELECT, camera,
        CAMERA_SELECTS[2])
    state = hass.states.get(entity_id)
    assert state
    assert len(state.attributes[ATTR_OPTIONS]) == expected_length
    expected_length += 1
    new_nvr = copy(mock_entry.api.bootstrap.nvr)
    new_nvr.__fields__['update_all_messages'] = Mock()
    new_nvr.update_all_messages = Mock()
    new_nvr.doorbell_settings.all_messages = [*new_nvr.doorbell_settings.
        all_messages, DoorbellMessage(type=DoorbellMessageType.
        CUSTOM_MESSAGE, text='Test2')]
    mock_msg = Mock()
    mock_msg.changed_data = {'doorbell_settings': {}}
    mock_msg.new_obj = new_nvr
    mock_entry.api.bootstrap.nvr = new_nvr
    mock_entry.api.ws_subscription(mock_msg)
    await hass.async_block_till_done()
    new_nvr.update_all_messages.assert_called_once()
    state = hass.states.get(entity_id)
    assert state
    assert len(state.attributes[ATTR_OPTIONS]) == expected_length


async def test_select_update_doorbell_message(hass: HomeAssistant,
    mock_entry: MockEntityFixture, camera: Camera):
    """Test select entity update (change doorbell message)."""
    _, entity_id = ids_from_device_description(Platform.SELECT, camera,
        CAMERA_SELECTS[2])
    state = hass.states.get(entity_id)
    assert state
    assert state.state == 'Default Message (Welcome)'
    new_bootstrap = copy(mock_entry.api.bootstrap)
    new_camera = camera.copy()
    new_camera.lcd_message = LCDMessage(type=DoorbellMessageType.
        CUSTOM_MESSAGE, text='Test')
    mock_msg = Mock()
    mock_msg.changed_data = {}
    mock_msg.new_obj = new_camera
    new_bootstrap.cameras = {new_camera.id: new_camera}
    mock_entry.api.bootstrap = new_bootstrap
    mock_entry.api.ws_subscription(mock_msg)
    await hass.async_block_till_done()
    state = hass.states.get(entity_id)
    assert state
    assert state.state == 'Test'


async def test_select_set_option_light_motion(hass: HomeAssistant, light: Light
    ):
    """Test Light Mode select."""
    _, entity_id = ids_from_device_description(Platform.SELECT, light,
        LIGHT_SELECTS[0])
    light.__fields__['set_light_settings'] = Mock()
    light.set_light_settings = AsyncMock()
    await hass.services.async_call('select', 'select_option', {
        ATTR_ENTITY_ID: entity_id, ATTR_OPTION: LIGHT_MODE_OFF}, blocking=True)
    light.set_light_settings.assert_called_once_with(LightModeType.MANUAL,
        enable_at=None)


async def test_select_set_option_light_camera(hass: HomeAssistant, light: Light
    ):
    """Test Paired Camera select."""
    _, entity_id = ids_from_device_description(Platform.SELECT, light,
        LIGHT_SELECTS[1])
    light.__fields__['set_paired_camera'] = Mock()
    light.set_paired_camera = AsyncMock()
    camera = list(light.api.bootstrap.cameras.values())[0]
    await hass.services.async_call('select', 'select_option', {
        ATTR_ENTITY_ID: entity_id, ATTR_OPTION: camera.name}, blocking=True)
    light.set_paired_camera.assert_called_once_with(camera)
    await hass.services.async_call('select', 'select_option', {
        ATTR_ENTITY_ID: entity_id, ATTR_OPTION: 'Not Paired'}, blocking=True)
    light.set_paired_camera.assert_called_with(None)


async def test_select_set_option_camera_recording(hass: HomeAssistant,
    camera: Camera):
    """Test Recording Mode select."""
    _, entity_id = ids_from_device_description(Platform.SELECT, camera,
        CAMERA_SELECTS[0])
    camera.__fields__['set_recording_mode'] = Mock()
    camera.set_recording_mode = AsyncMock()
    await hass.services.async_call('select', 'select_option', {
        ATTR_ENTITY_ID: entity_id, ATTR_OPTION: 'Never'}, blocking=True)
    camera.set_recording_mode.assert_called_once_with(RecordingMode.NEVER)


async def test_select_set_option_camera_ir(hass: HomeAssistant, camera: Camera
    ):
    """Test Infrared Mode select."""
    _, entity_id = ids_from_device_description(Platform.SELECT, camera,
        CAMERA_SELECTS[1])
    camera.__fields__['set_ir_led_model'] = Mock()
    camera.set_ir_led_model = AsyncMock()
    await hass.services.async_call('select', 'select_option', {
        ATTR_ENTITY_ID: entity_id, ATTR_OPTION: 'Always Enable'}, blocking=True
        )
    camera.set_ir_led_model.assert_called_once_with(IRLEDMode.ON)


async def test_select_set_option_camera_doorbell_custom(hass: HomeAssistant,
    camera: Camera):
    """Test Doorbell Text select (user defined message)."""
    _, entity_id = ids_from_device_description(Platform.SELECT, camera,
        CAMERA_SELECTS[2])
    camera.__fields__['set_lcd_text'] = Mock()
    camera.set_lcd_text = AsyncMock()
    await hass.services.async_call('select', 'select_option', {
        ATTR_ENTITY_ID: entity_id, ATTR_OPTION: 'Test'}, blocking=True)
    camera.set_lcd_text.assert_called_once_with(DoorbellMessageType.
        CUSTOM_MESSAGE, text='Test')


async def test_select_set_option_camera_doorbell_unifi(hass: HomeAssistant,
    camera: Camera):
    """Test Doorbell Text select (unifi message)."""
    _, entity_id = ids_from_device_description(Platform.SELECT, camera,
        CAMERA_SELECTS[2])
    camera.__fields__['set_lcd_text'] = Mock()
    camera.set_lcd_text = AsyncMock()
    await hass.services.async_call('select', 'select_option', {
        ATTR_ENTITY_ID: entity_id, ATTR_OPTION: 'LEAVE PACKAGE AT DOOR'},
        blocking=True)
    camera.set_lcd_text.assert_called_once_with(DoorbellMessageType.
        LEAVE_PACKAGE_AT_DOOR)
    await hass.services.async_call('select', 'select_option', {
        ATTR_ENTITY_ID: entity_id, ATTR_OPTION: 'Default Message (Welcome)'
        }, blocking=True)
    camera.set_lcd_text.assert_called_with(None)


async def test_select_set_option_camera_doorbell_default(hass:
    HomeAssistant, camera: Camera):
    """Test Doorbell Text select (default message)."""
    _, entity_id = ids_from_device_description(Platform.SELECT, camera,
        CAMERA_SELECTS[2])
    camera.__fields__['set_lcd_text'] = Mock()
    camera.set_lcd_text = AsyncMock()
    await hass.services.async_call('select', 'select_option', {
        ATTR_ENTITY_ID: entity_id, ATTR_OPTION: 'Default Message (Welcome)'
        }, blocking=True)
    camera.set_lcd_text.assert_called_once_with(None)


async def test_select_set_option_viewer(hass: HomeAssistant, viewer: Viewer):
    """Test Liveview select."""
    _, entity_id = ids_from_device_description(Platform.SELECT, viewer,
        VIEWER_SELECTS[0])
    viewer.__fields__['set_liveview'] = Mock()
    viewer.set_liveview = AsyncMock()
    liveview = list(viewer.api.bootstrap.liveviews.values())[0]
    await hass.services.async_call('select', 'select_option', {
        ATTR_ENTITY_ID: entity_id, ATTR_OPTION: liveview.name}, blocking=True)
    viewer.set_liveview.assert_called_once_with(liveview)


async def test_select_service_doorbell_invalid(hass: HomeAssistant, camera:
    Camera):
    """Test Doorbell Text service (invalid)."""
    _, entity_id = ids_from_device_description(Platform.SELECT, camera,
        CAMERA_SELECTS[1])
    camera.__fields__['set_lcd_text'] = Mock()
    camera.set_lcd_text = AsyncMock()
    with pytest.raises(HomeAssistantError):
        await hass.services.async_call('unifiprotect',
            SERVICE_SET_DOORBELL_MESSAGE, {ATTR_ENTITY_ID: entity_id,
            ATTR_MESSAGE: 'Test'}, blocking=True)
    assert not camera.set_lcd_text.called


async def test_select_service_doorbell_success(hass: HomeAssistant, camera:
    Camera):
    """Test Doorbell Text service (success)."""
    _, entity_id = ids_from_device_description(Platform.SELECT, camera,
        CAMERA_SELECTS[2])
    camera.__fields__['set_lcd_text'] = Mock()
    camera.set_lcd_text = AsyncMock()
    await hass.services.async_call('unifiprotect',
        SERVICE_SET_DOORBELL_MESSAGE, {ATTR_ENTITY_ID: entity_id,
        ATTR_MESSAGE: 'Test'}, blocking=True)
    camera.set_lcd_text.assert_called_once_with(DoorbellMessageType.
        CUSTOM_MESSAGE, 'Test', reset_at=None)


@patch('homeassistant.components.unifiprotect.select.utcnow')
async def test_select_service_doorbell_with_reset(mock_now, hass:
    HomeAssistant, camera: Camera):
    """Test Doorbell Text service (success with reset time)."""
    now = utcnow()
    mock_now.return_value = now
    _, entity_id = ids_from_device_description(Platform.SELECT, camera,
        CAMERA_SELECTS[2])
    camera.__fields__['set_lcd_text'] = Mock()
    camera.set_lcd_text = AsyncMock()
    await hass.services.async_call('unifiprotect',
        SERVICE_SET_DOORBELL_MESSAGE, {ATTR_ENTITY_ID: entity_id,
        ATTR_MESSAGE: 'Test', ATTR_DURATION: 60}, blocking=True)
    camera.set_lcd_text.assert_called_once_with(DoorbellMessageType.
        CUSTOM_MESSAGE, 'Test', reset_at=now + timedelta(minutes=60))

<mask token>
from __future__ import annotations
from copy import copy
from datetime import timedelta
from unittest.mock import AsyncMock, Mock, patch
import pytest
from pyunifiprotect.data import Camera, Light
from pyunifiprotect.data.devices import LCDMessage, Viewer
from pyunifiprotect.data.nvr import DoorbellMessage, Liveview
from pyunifiprotect.data.types import DoorbellMessageType, IRLEDMode, LightModeEnableType, LightModeType, RecordingMode
from homeassistant.components.select.const import ATTR_OPTIONS
from homeassistant.components.unifiprotect.const import ATTR_DURATION, ATTR_MESSAGE, DEFAULT_ATTRIBUTION
from homeassistant.components.unifiprotect.select import CAMERA_SELECTS, LIGHT_MODE_OFF, LIGHT_SELECTS, SERVICE_SET_DOORBELL_MESSAGE, VIEWER_SELECTS
from homeassistant.const import ATTR_ATTRIBUTION, ATTR_ENTITY_ID, ATTR_OPTION, Platform
from homeassistant.core import HomeAssistant
from homeassistant.exceptions import HomeAssistantError
from homeassistant.helpers import entity_registry as er
from homeassistant.util.dt import utcnow
from .conftest import MockEntityFixture, assert_entity_counts, ids_from_device_description


@pytest.fixture(name='viewer')
async def viewer_fixture(hass: HomeAssistant, mock_entry: MockEntityFixture,
    mock_viewer: Viewer, mock_liveview: Liveview):
    """Fixture for a single viewport for testing the select platform."""
    Viewer.__config__.validate_assignment = False
    viewer_obj = mock_viewer.copy(deep=True)
    viewer_obj._api = mock_entry.api
    viewer_obj.name = 'Test Viewer'
    viewer_obj.liveview_id = mock_liveview.id
    mock_entry.api.bootstrap.reset_objects()
    mock_entry.api.bootstrap.viewers = {viewer_obj.id: viewer_obj}
    mock_entry.api.bootstrap.liveviews = {mock_liveview.id: mock_liveview}
    await hass.config_entries.async_setup(mock_entry.entry.entry_id)
    await hass.async_block_till_done()
    assert_entity_counts(hass, Platform.SELECT, 1, 1)
    yield viewer_obj
    Viewer.__config__.validate_assignment = True


@pytest.fixture(name='camera')
async def camera_fixture(hass: HomeAssistant, mock_entry: MockEntityFixture,
    mock_camera: Camera):
    """Fixture for a single camera for testing the select platform."""
    Camera.__config__.validate_assignment = False
    camera_obj = mock_camera.copy(deep=True)
    camera_obj._api = mock_entry.api
    camera_obj.channels[0]._api = mock_entry.api
    camera_obj.channels[1]._api = mock_entry.api
    camera_obj.channels[2]._api = mock_entry.api
    camera_obj.name = 'Test Camera'
    camera_obj.feature_flags.has_lcd_screen = True
    camera_obj.feature_flags.has_chime = True
    camera_obj.recording_settings.mode = RecordingMode.ALWAYS
    camera_obj.isp_settings.ir_led_mode = IRLEDMode.AUTO
    camera_obj.lcd_message = None
    camera_obj.chime_duration = 0
    mock_entry.api.bootstrap.reset_objects()
    mock_entry.api.bootstrap.cameras = {camera_obj.id: camera_obj}
    await hass.config_entries.async_setup(mock_entry.entry.entry_id)
    await hass.async_block_till_done()
    assert_entity_counts(hass, Platform.SELECT, 4, 4)
    yield camera_obj
    Camera.__config__.validate_assignment = True


@pytest.fixture(name='light')
async def light_fixture(hass: HomeAssistant, mock_entry: MockEntityFixture,
    mock_light: Light, camera: Camera):
    """Fixture for a single light for testing the select platform."""
    Light.__config__.validate_assignment = False
    light_obj = mock_light.copy(deep=True)
    light_obj._api = mock_entry.api
    light_obj.name = 'Test Light'
    light_obj.camera_id = None
    light_obj.light_mode_settings.mode = LightModeType.MOTION
    light_obj.light_mode_settings.enable_at = LightModeEnableType.DARK
    mock_entry.api.bootstrap.reset_objects()
    mock_entry.api.bootstrap.cameras = {camera.id: camera}
    mock_entry.api.bootstrap.lights = {light_obj.id: light_obj}
    await hass.config_entries.async_reload(mock_entry.entry.entry_id)
    await hass.async_block_till_done()
    assert_entity_counts(hass, Platform.SELECT, 6, 6)
    yield light_obj
    Light.__config__.validate_assignment = True


@pytest.fixture(name='camera_none')
async def camera_none_fixture(hass: HomeAssistant, mock_entry:
    MockEntityFixture, mock_camera: Camera):
    """Fixture for a single camera for testing the select platform."""
    Camera.__config__.validate_assignment = False
    camera_obj = mock_camera.copy(deep=True)
    camera_obj._api = mock_entry.api
    camera_obj.channels[0]._api = mock_entry.api
    camera_obj.channels[1]._api = mock_entry.api
    camera_obj.channels[2]._api = mock_entry.api
    camera_obj.name = 'Test Camera'
    camera_obj.feature_flags.has_lcd_screen = False
    camera_obj.feature_flags.has_chime = False
    camera_obj.recording_settings.mode = RecordingMode.ALWAYS
    camera_obj.isp_settings.ir_led_mode = IRLEDMode.AUTO
    mock_entry.api.bootstrap.reset_objects()
    mock_entry.api.bootstrap.cameras = {camera_obj.id: camera_obj}
    await hass.config_entries.async_setup(mock_entry.entry.entry_id)
    await hass.async_block_till_done()
    assert_entity_counts(hass, Platform.SELECT, 2, 2)
    yield camera_obj
    Camera.__config__.validate_assignment = True


async def test_select_setup_light(hass: HomeAssistant, light: Light):
    """Test select entity setup for light devices."""
    entity_registry = er.async_get(hass)
    expected_values = 'On Motion - When Dark', 'Not Paired'
    for index, description in enumerate(LIGHT_SELECTS):
        unique_id, entity_id = ids_from_device_description(Platform.SELECT,
            light, description)
        entity = entity_registry.async_get(entity_id)
        assert entity
        assert entity.unique_id == unique_id
        state = hass.states.get(entity_id)
        assert state
        assert state.state == expected_values[index]
        assert state.attributes[ATTR_ATTRIBUTION] == DEFAULT_ATTRIBUTION


async def test_select_setup_viewer(hass: HomeAssistant, viewer: Viewer):
    """Test select entity setup for light devices."""
    entity_registry = er.async_get(hass)
    description = VIEWER_SELECTS[0]
    unique_id, entity_id = ids_from_device_description(Platform.SELECT,
        viewer, description)
    entity = entity_registry.async_get(entity_id)
    assert entity
    assert entity.unique_id == unique_id
    state = hass.states.get(entity_id)
    assert state
    assert state.state == viewer.liveview.name
    assert state.attributes[ATTR_ATTRIBUTION] == DEFAULT_ATTRIBUTION


async def test_select_setup_camera_all(hass: HomeAssistant, camera: Camera):
    """Test select entity setup for camera devices (all features)."""
    entity_registry = er.async_get(hass)
    expected_values = 'Always', 'Auto', 'Default Message (Welcome)', 'None'
    for index, description in enumerate(CAMERA_SELECTS):
        unique_id, entity_id = ids_from_device_description(Platform.SELECT,
            camera, description)
        entity = entity_registry.async_get(entity_id)
        assert entity
        assert entity.unique_id == unique_id
        state = hass.states.get(entity_id)
        assert state
        assert state.state == expected_values[index]
        assert state.attributes[ATTR_ATTRIBUTION] == DEFAULT_ATTRIBUTION


async def test_select_setup_camera_none(hass: HomeAssistant, camera_none:
    Camera):
    """Test select entity setup for camera devices (no features)."""
    entity_registry = er.async_get(hass)
    expected_values = 'Always', 'Auto', 'Default Message (Welcome)'
    for index, description in enumerate(CAMERA_SELECTS):
        if index == 2:
            return
        unique_id, entity_id = ids_from_device_description(Platform.SELECT,
            camera_none, description)
        entity = entity_registry.async_get(entity_id)
        assert entity
        assert entity.unique_id == unique_id
        state = hass.states.get(entity_id)
        assert state
        assert state.state == expected_values[index]
        assert state.attributes[ATTR_ATTRIBUTION] == DEFAULT_ATTRIBUTION


async def test_select_update_liveview(hass: HomeAssistant, mock_entry:
    MockEntityFixture, viewer: Viewer, mock_liveview: Liveview):
    """Test select entity update (new Liveview)."""
    _, entity_id = ids_from_device_description(Platform.SELECT, viewer,
        VIEWER_SELECTS[0])
    state = hass.states.get(entity_id)
    assert state
    expected_options = state.attributes[ATTR_OPTIONS]
    new_bootstrap = copy(mock_entry.api.bootstrap)
    new_liveview = copy(mock_liveview)
    new_liveview.id = 'test_id'
    mock_msg = Mock()
    mock_msg.changed_data = {}
    mock_msg.new_obj = new_liveview
    new_bootstrap.liveviews = {**new_bootstrap.liveviews, new_liveview.id:
        new_liveview}
    mock_entry.api.bootstrap = new_bootstrap
    mock_entry.api.ws_subscription(mock_msg)
    await hass.async_block_till_done()
    state = hass.states.get(entity_id)
    assert state
    assert state.attributes[ATTR_OPTIONS] == expected_options


async def test_select_update_doorbell_settings(hass: HomeAssistant,
    mock_entry: MockEntityFixture, camera: Camera):
    """Test select entity update (new Doorbell Message)."""
    expected_length = len(mock_entry.api.bootstrap.nvr.doorbell_settings.
        all_messages) + 1
    _, entity_id = ids_from_device_description(Platform.SELECT, camera,
        CAMERA_SELECTS[2])
    state = hass.states.get(entity_id)
    assert state
    assert len(state.attributes[ATTR_OPTIONS]) == expected_length
    expected_length += 1
    new_nvr = copy(mock_entry.api.bootstrap.nvr)
    new_nvr.__fields__['update_all_messages'] = Mock()
    new_nvr.update_all_messages = Mock()
    new_nvr.doorbell_settings.all_messages = [*new_nvr.doorbell_settings.
        all_messages, DoorbellMessage(type=DoorbellMessageType.
        CUSTOM_MESSAGE, text='Test2')]
    mock_msg = Mock()
    mock_msg.changed_data = {'doorbell_settings': {}}
    mock_msg.new_obj = new_nvr
    mock_entry.api.bootstrap.nvr = new_nvr
    mock_entry.api.ws_subscription(mock_msg)
    await hass.async_block_till_done()
    new_nvr.update_all_messages.assert_called_once()
    state = hass.states.get(entity_id)
    assert state
    assert len(state.attributes[ATTR_OPTIONS]) == expected_length


async def test_select_update_doorbell_message(hass: HomeAssistant,
    mock_entry: MockEntityFixture, camera: Camera):
    """Test select entity update (change doorbell message)."""
    _, entity_id = ids_from_device_description(Platform.SELECT, camera,
        CAMERA_SELECTS[2])
    state = hass.states.get(entity_id)
    assert state
    assert state.state == 'Default Message (Welcome)'
    new_bootstrap = copy(mock_entry.api.bootstrap)
    new_camera = camera.copy()
    new_camera.lcd_message = LCDMessage(type=DoorbellMessageType.
        CUSTOM_MESSAGE, text='Test')
    mock_msg = Mock()
    mock_msg.changed_data = {}
    mock_msg.new_obj = new_camera
    new_bootstrap.cameras = {new_camera.id: new_camera}
    mock_entry.api.bootstrap = new_bootstrap
    mock_entry.api.ws_subscription(mock_msg)
    await hass.async_block_till_done()
    state = hass.states.get(entity_id)
    assert state
    assert state.state == 'Test'


async def test_select_set_option_light_motion(hass: HomeAssistant, light: Light
    ):
    """Test Light Mode select."""
    _, entity_id = ids_from_device_description(Platform.SELECT, light,
        LIGHT_SELECTS[0])
    light.__fields__['set_light_settings'] = Mock()
    light.set_light_settings = AsyncMock()
    await hass.services.async_call('select', 'select_option', {
        ATTR_ENTITY_ID: entity_id, ATTR_OPTION: LIGHT_MODE_OFF}, blocking=True)
    light.set_light_settings.assert_called_once_with(LightModeType.MANUAL,
        enable_at=None)


async def test_select_set_option_light_camera(hass: HomeAssistant, light: Light
    ):
    """Test Paired Camera select."""
    _, entity_id = ids_from_device_description(Platform.SELECT, light,
        LIGHT_SELECTS[1])
    light.__fields__['set_paired_camera'] = Mock()
    light.set_paired_camera = AsyncMock()
    camera = list(light.api.bootstrap.cameras.values())[0]
    await hass.services.async_call('select', 'select_option', {
        ATTR_ENTITY_ID: entity_id, ATTR_OPTION: camera.name}, blocking=True)
    light.set_paired_camera.assert_called_once_with(camera)
    await hass.services.async_call('select', 'select_option', {
        ATTR_ENTITY_ID: entity_id, ATTR_OPTION: 'Not Paired'}, blocking=True)
    light.set_paired_camera.assert_called_with(None)


async def test_select_set_option_camera_recording(hass: HomeAssistant,
    camera: Camera):
    """Test Recording Mode select."""
    _, entity_id = ids_from_device_description(Platform.SELECT, camera,
        CAMERA_SELECTS[0])
    camera.__fields__['set_recording_mode'] = Mock()
    camera.set_recording_mode = AsyncMock()
    await hass.services.async_call('select', 'select_option', {
        ATTR_ENTITY_ID: entity_id, ATTR_OPTION: 'Never'}, blocking=True)
    camera.set_recording_mode.assert_called_once_with(RecordingMode.NEVER)


async def test_select_set_option_camera_ir(hass: HomeAssistant, camera: Camera
    ):
    """Test Infrared Mode select."""
    _, entity_id = ids_from_device_description(Platform.SELECT, camera,
        CAMERA_SELECTS[1])
    camera.__fields__['set_ir_led_model'] = Mock()
    camera.set_ir_led_model = AsyncMock()
    await hass.services.async_call('select', 'select_option', {
        ATTR_ENTITY_ID: entity_id, ATTR_OPTION: 'Always Enable'}, blocking=True
        )
    camera.set_ir_led_model.assert_called_once_with(IRLEDMode.ON)


async def test_select_set_option_camera_doorbell_custom(hass: HomeAssistant,
    camera: Camera):
    """Test Doorbell Text select (user defined message)."""
    _, entity_id = ids_from_device_description(Platform.SELECT, camera,
        CAMERA_SELECTS[2])
    camera.__fields__['set_lcd_text'] = Mock()
    camera.set_lcd_text = AsyncMock()
    await hass.services.async_call('select', 'select_option', {
        ATTR_ENTITY_ID: entity_id, ATTR_OPTION: 'Test'}, blocking=True)
    camera.set_lcd_text.assert_called_once_with(DoorbellMessageType.
        CUSTOM_MESSAGE, text='Test')


async def test_select_set_option_camera_doorbell_unifi(hass: HomeAssistant,
    camera: Camera):
    """Test Doorbell Text select (unifi message)."""
    _, entity_id = ids_from_device_description(Platform.SELECT, camera,
        CAMERA_SELECTS[2])
    camera.__fields__['set_lcd_text'] = Mock()
    camera.set_lcd_text = AsyncMock()
    await hass.services.async_call('select', 'select_option', {
        ATTR_ENTITY_ID: entity_id, ATTR_OPTION: 'LEAVE PACKAGE AT DOOR'},
        blocking=True)
    camera.set_lcd_text.assert_called_once_with(DoorbellMessageType.
        LEAVE_PACKAGE_AT_DOOR)
    await hass.services.async_call('select', 'select_option', {
        ATTR_ENTITY_ID: entity_id, ATTR_OPTION: 'Default Message (Welcome)'
        }, blocking=True)
    camera.set_lcd_text.assert_called_with(None)


async def test_select_set_option_camera_doorbell_default(hass:
    HomeAssistant, camera: Camera):
    """Test Doorbell Text select (default message)."""
    _, entity_id = ids_from_device_description(Platform.SELECT, camera,
        CAMERA_SELECTS[2])
    camera.__fields__['set_lcd_text'] = Mock()
    camera.set_lcd_text = AsyncMock()
    await hass.services.async_call('select', 'select_option', {
        ATTR_ENTITY_ID: entity_id, ATTR_OPTION: 'Default Message (Welcome)'
        }, blocking=True)
    camera.set_lcd_text.assert_called_once_with(None)


async def test_select_set_option_viewer(hass: HomeAssistant, viewer: Viewer):
    """Test Liveview select."""
    _, entity_id = ids_from_device_description(Platform.SELECT, viewer,
        VIEWER_SELECTS[0])
    viewer.__fields__['set_liveview'] = Mock()
    viewer.set_liveview = AsyncMock()
    liveview = list(viewer.api.bootstrap.liveviews.values())[0]
    await hass.services.async_call('select', 'select_option', {
        ATTR_ENTITY_ID: entity_id, ATTR_OPTION: liveview.name}, blocking=True)
    viewer.set_liveview.assert_called_once_with(liveview)


async def test_select_service_doorbell_invalid(hass: HomeAssistant, camera:
    Camera):
    """Test Doorbell Text service (invalid)."""
    _, entity_id = ids_from_device_description(Platform.SELECT, camera,
        CAMERA_SELECTS[1])
    camera.__fields__['set_lcd_text'] = Mock()
    camera.set_lcd_text = AsyncMock()
    with pytest.raises(HomeAssistantError):
        await hass.services.async_call('unifiprotect',
            SERVICE_SET_DOORBELL_MESSAGE, {ATTR_ENTITY_ID: entity_id,
            ATTR_MESSAGE: 'Test'}, blocking=True)
    assert not camera.set_lcd_text.called


async def test_select_service_doorbell_success(hass: HomeAssistant, camera:
    Camera):
    """Test Doorbell Text service (success)."""
    _, entity_id = ids_from_device_description(Platform.SELECT, camera,
        CAMERA_SELECTS[2])
    camera.__fields__['set_lcd_text'] = Mock()
    camera.set_lcd_text = AsyncMock()
    await hass.services.async_call('unifiprotect',
        SERVICE_SET_DOORBELL_MESSAGE, {ATTR_ENTITY_ID: entity_id,
        ATTR_MESSAGE: 'Test'}, blocking=True)
    camera.set_lcd_text.assert_called_once_with(DoorbellMessageType.
        CUSTOM_MESSAGE, 'Test', reset_at=None)


@patch('homeassistant.components.unifiprotect.select.utcnow')
async def test_select_service_doorbell_with_reset(mock_now, hass:
    HomeAssistant, camera: Camera):
    """Test Doorbell Text service (success with reset time)."""
    now = utcnow()
    mock_now.return_value = now
    _, entity_id = ids_from_device_description(Platform.SELECT, camera,
        CAMERA_SELECTS[2])
    camera.__fields__['set_lcd_text'] = Mock()
    camera.set_lcd_text = AsyncMock()
    await hass.services.async_call('unifiprotect',
        SERVICE_SET_DOORBELL_MESSAGE, {ATTR_ENTITY_ID: entity_id,
        ATTR_MESSAGE: 'Test', ATTR_DURATION: 60}, blocking=True)
    camera.set_lcd_text.assert_called_once_with(DoorbellMessageType.
        CUSTOM_MESSAGE, 'Test', reset_at=now + timedelta(minutes=60))

"""Test the UniFi Protect select platform."""
# pylint: disable=protected-access
from __future__ import annotations

from copy import copy
from datetime import timedelta
from unittest.mock import AsyncMock, Mock, patch

import pytest
from pyunifiprotect.data import Camera, Light
from pyunifiprotect.data.devices import LCDMessage, Viewer
from pyunifiprotect.data.nvr import DoorbellMessage, Liveview
from pyunifiprotect.data.types import (
    DoorbellMessageType,
    IRLEDMode,
    LightModeEnableType,
    LightModeType,
    RecordingMode,
)

from homeassistant.components.select.const import ATTR_OPTIONS
from homeassistant.components.unifiprotect.const import (
    ATTR_DURATION,
    ATTR_MESSAGE,
    DEFAULT_ATTRIBUTION,
)
from homeassistant.components.unifiprotect.select import (
    CAMERA_SELECTS,
    LIGHT_MODE_OFF,
    LIGHT_SELECTS,
    SERVICE_SET_DOORBELL_MESSAGE,
    VIEWER_SELECTS,
)
from homeassistant.const import ATTR_ATTRIBUTION, ATTR_ENTITY_ID, ATTR_OPTION, Platform
from homeassistant.core import HomeAssistant
from homeassistant.exceptions import HomeAssistantError
from homeassistant.helpers import entity_registry as er
from homeassistant.util.dt import utcnow

from .conftest import (
    MockEntityFixture,
    assert_entity_counts,
    ids_from_device_description,
)


@pytest.fixture(name="viewer")
async def viewer_fixture(
    hass: HomeAssistant,
    mock_entry: MockEntityFixture,
    mock_viewer: Viewer,
    mock_liveview: Liveview,
):
    """Fixture for a single viewport for testing the select platform."""

    # disable pydantic validation so mocking can happen
    Viewer.__config__.validate_assignment = False

    viewer_obj = mock_viewer.copy(deep=True)
    viewer_obj._api = mock_entry.api
    viewer_obj.name = "Test Viewer"
    viewer_obj.liveview_id = mock_liveview.id

    mock_entry.api.bootstrap.reset_objects()
    mock_entry.api.bootstrap.viewers = {
        viewer_obj.id: viewer_obj,
    }
    mock_entry.api.bootstrap.liveviews = {mock_liveview.id: mock_liveview}

    await hass.config_entries.async_setup(mock_entry.entry.entry_id)
    await hass.async_block_till_done()

    assert_entity_counts(hass, Platform.SELECT, 1, 1)

    yield viewer_obj

    Viewer.__config__.validate_assignment = True


@pytest.fixture(name="camera")
async def camera_fixture(
    hass: HomeAssistant, mock_entry: MockEntityFixture, mock_camera: Camera
):
    """Fixture for a single camera for testing the select platform."""

    # disable pydantic validation so mocking can happen
    Camera.__config__.validate_assignment = False

    camera_obj = mock_camera.copy(deep=True)
    camera_obj._api = mock_entry.api
    camera_obj.channels[0]._api = mock_entry.api
    camera_obj.channels[1]._api = mock_entry.api
    camera_obj.channels[2]._api = mock_entry.api
    camera_obj.name = "Test Camera"
    camera_obj.feature_flags.has_lcd_screen = True
    camera_obj.feature_flags.has_chime = True
    camera_obj.recording_settings.mode = RecordingMode.ALWAYS
    camera_obj.isp_settings.ir_led_mode = IRLEDMode.AUTO
    camera_obj.lcd_message = None
    camera_obj.chime_duration = 0

    mock_entry.api.bootstrap.reset_objects()
    mock_entry.api.bootstrap.cameras = {
        camera_obj.id: camera_obj,
    }

    await hass.config_entries.async_setup(mock_entry.entry.entry_id)
    await hass.async_block_till_done()

    assert_entity_counts(hass, Platform.SELECT, 4, 4)

    yield camera_obj

    Camera.__config__.validate_assignment = True


@pytest.fixture(name="light")
async def light_fixture(
    hass: HomeAssistant,
    mock_entry: MockEntityFixture,
    mock_light: Light,
    camera: Camera,
):
    """Fixture for a single light for testing the select platform."""

    # disable pydantic validation so mocking can happen
    Light.__config__.validate_assignment = False

    light_obj = mock_light.copy(deep=True)
    light_obj._api = mock_entry.api
    light_obj.name = "Test Light"
    light_obj.camera_id = None
    light_obj.light_mode_settings.mode = LightModeType.MOTION
    light_obj.light_mode_settings.enable_at = LightModeEnableType.DARK

    mock_entry.api.bootstrap.reset_objects()
    mock_entry.api.bootstrap.cameras = {camera.id: camera}
    mock_entry.api.bootstrap.lights = {
        light_obj.id: light_obj,
    }

    await hass.config_entries.async_reload(mock_entry.entry.entry_id)
    await hass.async_block_till_done()

    assert_entity_counts(hass, Platform.SELECT, 6, 6)

    yield light_obj

    Light.__config__.validate_assignment = True


@pytest.fixture(name="camera_none")
async def camera_none_fixture(
    hass: HomeAssistant, mock_entry: MockEntityFixture, mock_camera: Camera
):
    """Fixture for a single camera for testing the select platform."""

    # disable pydantic validation so mocking can happen
    Camera.__config__.validate_assignment = False

    camera_obj = mock_camera.copy(deep=True)
    camera_obj._api = mock_entry.api
    camera_obj.channels[0]._api = mock_entry.api
    camera_obj.channels[1]._api = mock_entry.api
    camera_obj.channels[2]._api = mock_entry.api
    camera_obj.name = "Test Camera"
    camera_obj.feature_flags.has_lcd_screen = False
    camera_obj.feature_flags.has_chime = False
    camera_obj.recording_settings.mode = RecordingMode.ALWAYS
    camera_obj.isp_settings.ir_led_mode = IRLEDMode.AUTO

    mock_entry.api.bootstrap.reset_objects()
    mock_entry.api.bootstrap.cameras = {
        camera_obj.id: camera_obj,
    }

    await hass.config_entries.async_setup(mock_entry.entry.entry_id)
    await hass.async_block_till_done()

    assert_entity_counts(hass, Platform.SELECT, 2, 2)

    yield camera_obj

    Camera.__config__.validate_assignment = True


async def test_select_setup_light(
    hass: HomeAssistant,
    light: Light,
):
    """Test select entity setup for light devices."""

    entity_registry = er.async_get(hass)
    expected_values = ("On Motion - When Dark", "Not Paired")

    for index, description in enumerate(LIGHT_SELECTS):
        unique_id, entity_id = ids_from_device_description(
            Platform.SELECT, light, description
        )

        entity = entity_registry.async_get(entity_id)
        assert entity
        assert entity.unique_id == unique_id

        state = hass.states.get(entity_id)
        assert state
        assert state.state == expected_values[index]
        assert state.attributes[ATTR_ATTRIBUTION] == DEFAULT_ATTRIBUTION


async def test_select_setup_viewer(
    hass: HomeAssistant,
    viewer: Viewer,
):
    """Test select entity setup for light devices."""

    entity_registry = er.async_get(hass)
    description = VIEWER_SELECTS[0]

    unique_id, entity_id = ids_from_device_description(
        Platform.SELECT, viewer, description
    )

    entity = entity_registry.async_get(entity_id)
    assert entity
    assert entity.unique_id == unique_id

    state = hass.states.get(entity_id)
    assert state
    assert state.state == viewer.liveview.name
    assert state.attributes[ATTR_ATTRIBUTION] == DEFAULT_ATTRIBUTION


async def test_select_setup_camera_all(
    hass: HomeAssistant,
    camera: Camera,
):
    """Test select entity setup for camera devices (all features)."""

    entity_registry = er.async_get(hass)
    expected_values = ("Always", "Auto", "Default Message (Welcome)", "None")

    for index, description in enumerate(CAMERA_SELECTS):
        unique_id, entity_id = ids_from_device_description(
            Platform.SELECT, camera, description
        )

        entity = entity_registry.async_get(entity_id)
        assert entity
        assert entity.unique_id == unique_id

        state = hass.states.get(entity_id)
        assert state
        assert state.state == expected_values[index]
        assert state.attributes[ATTR_ATTRIBUTION] == DEFAULT_ATTRIBUTION


async def test_select_setup_camera_none(
    hass: HomeAssistant,
    camera_none: Camera,
):
    """Test select entity setup for camera devices (no features)."""

    entity_registry = er.async_get(hass)
    expected_values = ("Always", "Auto", "Default Message (Welcome)")

    for index, description in enumerate(CAMERA_SELECTS):
        if index == 2:
            return

        unique_id, entity_id = ids_from_device_description(
            Platform.SELECT, camera_none, description
        )

        entity = entity_registry.async_get(entity_id)
        assert entity
        assert entity.unique_id == unique_id

        state = hass.states.get(entity_id)
        assert state
        assert state.state == expected_values[index]
        assert state.attributes[ATTR_ATTRIBUTION] == DEFAULT_ATTRIBUTION


async def test_select_update_liveview(
    hass: HomeAssistant,
    mock_entry: MockEntityFixture,
    viewer: Viewer,
    mock_liveview: Liveview,
):
    """Test select entity update (new Liveview)."""

    _, entity_id = ids_from_device_description(
        Platform.SELECT, viewer, VIEWER_SELECTS[0]
    )

    state = hass.states.get(entity_id)
    assert state
    expected_options = state.attributes[ATTR_OPTIONS]

    new_bootstrap = copy(mock_entry.api.bootstrap)
    new_liveview = copy(mock_liveview)
    new_liveview.id = "test_id"

    mock_msg = Mock()
    mock_msg.changed_data = {}
    mock_msg.new_obj = new_liveview

    new_bootstrap.liveviews = {**new_bootstrap.liveviews, new_liveview.id: new_liveview}
    mock_entry.api.bootstrap = new_bootstrap
    mock_entry.api.ws_subscription(mock_msg)
    await hass.async_block_till_done()

    state = hass.states.get(entity_id)
    assert state
    assert state.attributes[ATTR_OPTIONS] == expected_options


async def test_select_update_doorbell_settings(
    hass: HomeAssistant, mock_entry: MockEntityFixture, camera: Camera
):
    """Test select entity update (new Doorbell Message)."""

    expected_length = (
        len(mock_entry.api.bootstrap.nvr.doorbell_settings.all_messages) + 1
    )

    _, entity_id = ids_from_device_description(
        Platform.SELECT, camera, CAMERA_SELECTS[2]
    )

    state = hass.states.get(entity_id)
    assert state
    assert len(state.attributes[ATTR_OPTIONS]) == expected_length

    expected_length += 1
    new_nvr = copy(mock_entry.api.bootstrap.nvr)
    new_nvr.__fields__["update_all_messages"] = Mock()
    new_nvr.update_all_messages = Mock()

    new_nvr.doorbell_settings.all_messages = [
        *new_nvr.doorbell_settings.all_messages,
        DoorbellMessage(
            type=DoorbellMessageType.CUSTOM_MESSAGE,
            text="Test2",
        ),
    ]

    mock_msg = Mock()
    mock_msg.changed_data = {"doorbell_settings": {}}
    mock_msg.new_obj = new_nvr

    mock_entry.api.bootstrap.nvr = new_nvr
    mock_entry.api.ws_subscription(mock_msg)
    await hass.async_block_till_done()

    new_nvr.update_all_messages.assert_called_once()

    state = hass.states.get(entity_id)
    assert state
    assert len(state.attributes[ATTR_OPTIONS]) == expected_length


async def test_select_update_doorbell_message(
    hass: HomeAssistant,
    mock_entry: MockEntityFixture,
    camera: Camera,
):
    """Test select entity update (change doorbell message)."""

    _, entity_id = ids_from_device_description(
        Platform.SELECT, camera, CAMERA_SELECTS[2]
    )

    state = hass.states.get(entity_id)
    assert state
    assert state.state == "Default Message (Welcome)"

    new_bootstrap = copy(mock_entry.api.bootstrap)
    new_camera = camera.copy()
    new_camera.lcd_message = LCDMessage(
        type=DoorbellMessageType.CUSTOM_MESSAGE, text="Test"
    )

    mock_msg = Mock()
    mock_msg.changed_data = {}
    mock_msg.new_obj = new_camera

    new_bootstrap.cameras = {new_camera.id: new_camera}
    mock_entry.api.bootstrap = new_bootstrap
    mock_entry.api.ws_subscription(mock_msg)
    await hass.async_block_till_done()

    state = hass.states.get(entity_id)
    assert state
    assert state.state == "Test"


async def test_select_set_option_light_motion(
    hass: HomeAssistant,
    light: Light,
):
    """Test Light Mode select."""
    _, entity_id = ids_from_device_description(Platform.SELECT, light, LIGHT_SELECTS[0])

    light.__fields__["set_light_settings"] = Mock()
    light.set_light_settings = AsyncMock()

    await hass.services.async_call(
        "select",
        "select_option",
        {ATTR_ENTITY_ID: entity_id, ATTR_OPTION: LIGHT_MODE_OFF},
        blocking=True,
    )

    light.set_light_settings.assert_called_once_with(
        LightModeType.MANUAL, enable_at=None
    )


async def test_select_set_option_light_camera(
    hass: HomeAssistant,
    light: Light,
):
    """Test Paired Camera select."""
    _, entity_id = ids_from_device_description(Platform.SELECT, light, LIGHT_SELECTS[1])

    light.__fields__["set_paired_camera"] = Mock()
    light.set_paired_camera = AsyncMock()

    camera = list(light.api.bootstrap.cameras.values())[0]

    await hass.services.async_call(
        "select",
        "select_option",
        {ATTR_ENTITY_ID: entity_id, ATTR_OPTION: camera.name},
        blocking=True,
    )

    light.set_paired_camera.assert_called_once_with(camera)

    await hass.services.async_call(
        "select",
        "select_option",
        {ATTR_ENTITY_ID: entity_id, ATTR_OPTION: "Not Paired"},
        blocking=True,
    )

    light.set_paired_camera.assert_called_with(None)


async def test_select_set_option_camera_recording(
    hass: HomeAssistant,
    camera: Camera,
):
    """Test Recording Mode select."""
    _, entity_id = ids_from_device_description(
        Platform.SELECT, camera, CAMERA_SELECTS[0]
    )

    camera.__fields__["set_recording_mode"] = Mock()
    camera.set_recording_mode = AsyncMock()

    await hass.services.async_call(
        "select",
        "select_option",
        {ATTR_ENTITY_ID: entity_id, ATTR_OPTION: "Never"},
        blocking=True,
    )

    camera.set_recording_mode.assert_called_once_with(RecordingMode.NEVER)


async def test_select_set_option_camera_ir(
    hass: HomeAssistant,
    camera: Camera,
):
    """Test Infrared Mode select."""
    _, entity_id = ids_from_device_description(
        Platform.SELECT, camera, CAMERA_SELECTS[1]
    )

    camera.__fields__["set_ir_led_model"] = Mock()
    camera.set_ir_led_model = AsyncMock()

    await hass.services.async_call(
        "select",
        "select_option",
        {ATTR_ENTITY_ID: entity_id, ATTR_OPTION: "Always Enable"},
        blocking=True,
    )

    camera.set_ir_led_model.assert_called_once_with(IRLEDMode.ON)


async def test_select_set_option_camera_doorbell_custom(
    hass: HomeAssistant,
    camera: Camera,
):
    """Test Doorbell Text select (user defined message)."""
    _, entity_id = ids_from_device_description(
        Platform.SELECT, camera, CAMERA_SELECTS[2]
    )

    camera.__fields__["set_lcd_text"] = Mock()
    camera.set_lcd_text = AsyncMock()

    await hass.services.async_call(
        "select",
        "select_option",
        {ATTR_ENTITY_ID: entity_id, ATTR_OPTION: "Test"},
        blocking=True,
    )

    camera.set_lcd_text.assert_called_once_with(
        DoorbellMessageType.CUSTOM_MESSAGE, text="Test"
    )


async def test_select_set_option_camera_doorbell_unifi(
    hass: HomeAssistant,
    camera: Camera,
):
    """Test Doorbell Text select (unifi message)."""
    _, entity_id = ids_from_device_description(
        Platform.SELECT, camera, CAMERA_SELECTS[2]
    )

    camera.__fields__["set_lcd_text"] = Mock()
    camera.set_lcd_text = AsyncMock()

    await hass.services.async_call(
        "select",
        "select_option",
        {
            ATTR_ENTITY_ID: entity_id,
            ATTR_OPTION: "LEAVE PACKAGE AT DOOR",
        },
        blocking=True,
    )

    camera.set_lcd_text.assert_called_once_with(
        DoorbellMessageType.LEAVE_PACKAGE_AT_DOOR
    )

    await hass.services.async_call(
        "select",
        "select_option",
        {
            ATTR_ENTITY_ID: entity_id,
            ATTR_OPTION: "Default Message (Welcome)",
        },
        blocking=True,
    )

    camera.set_lcd_text.assert_called_with(None)


async def test_select_set_option_camera_doorbell_default(
    hass: HomeAssistant,
    camera: Camera,
):
    """Test Doorbell Text select (default message)."""
    _, entity_id = ids_from_device_description(
        Platform.SELECT, camera, CAMERA_SELECTS[2]
    )

    camera.__fields__["set_lcd_text"] = Mock()
    camera.set_lcd_text = AsyncMock()

    await hass.services.async_call(
        "select",
        "select_option",
        {
            ATTR_ENTITY_ID: entity_id,
            ATTR_OPTION: "Default Message (Welcome)",
        },
        blocking=True,
    )

    camera.set_lcd_text.assert_called_once_with(None)


async def test_select_set_option_viewer(
    hass: HomeAssistant,
    viewer: Viewer,
):
    """Test Liveview select."""
    _, entity_id = ids_from_device_description(
        Platform.SELECT, viewer, VIEWER_SELECTS[0]
    )

    viewer.__fields__["set_liveview"] = Mock()
    viewer.set_liveview = AsyncMock()

    liveview = list(viewer.api.bootstrap.liveviews.values())[0]

    await hass.services.async_call(
        "select",
        "select_option",
        {ATTR_ENTITY_ID: entity_id, ATTR_OPTION: liveview.name},
        blocking=True,
    )

    viewer.set_liveview.assert_called_once_with(liveview)


async def test_select_service_doorbell_invalid(
    hass: HomeAssistant,
    camera: Camera,
):
    """Test Doorbell Text service (invalid)."""
    _, entity_id = ids_from_device_description(
        Platform.SELECT, camera, CAMERA_SELECTS[1]
    )

    camera.__fields__["set_lcd_text"] = Mock()
    camera.set_lcd_text = AsyncMock()

    with pytest.raises(HomeAssistantError):
        await hass.services.async_call(
            "unifiprotect",
            SERVICE_SET_DOORBELL_MESSAGE,
            {ATTR_ENTITY_ID: entity_id, ATTR_MESSAGE: "Test"},
            blocking=True,
        )

    assert not camera.set_lcd_text.called


async def test_select_service_doorbell_success(
    hass: HomeAssistant,
    camera: Camera,
):
    """Test Doorbell Text service (success)."""
    _, entity_id = ids_from_device_description(
        Platform.SELECT, camera, CAMERA_SELECTS[2]
    )

    camera.__fields__["set_lcd_text"] = Mock()
    camera.set_lcd_text = AsyncMock()

    await hass.services.async_call(
        "unifiprotect",
        SERVICE_SET_DOORBELL_MESSAGE,
        {
            ATTR_ENTITY_ID: entity_id,
            ATTR_MESSAGE: "Test",
        },
        blocking=True,
    )

    camera.set_lcd_text.assert_called_once_with(
        DoorbellMessageType.CUSTOM_MESSAGE, "Test", reset_at=None
    )


@patch("homeassistant.components.unifiprotect.select.utcnow")
async def test_select_service_doorbell_with_reset(
    mock_now,
    hass: HomeAssistant,
    camera: Camera,
):
    """Test Doorbell Text service (success with reset time)."""
    now = utcnow()
    mock_now.return_value = now

    _, entity_id = ids_from_device_description(
        Platform.SELECT, camera, CAMERA_SELECTS[2]
    )

    camera.__fields__["set_lcd_text"] = Mock()
    camera.set_lcd_text = AsyncMock()

    await hass.services.async_call(
        "unifiprotect",
        SERVICE_SET_DOORBELL_MESSAGE,
        {
            ATTR_ENTITY_ID: entity_id,
            ATTR_MESSAGE: "Test",
            ATTR_DURATION: 60,
        },
        blocking=True,
    )

    camera.set_lcd_text.assert_called_once_with(
        DoorbellMessageType.CUSTOM_MESSAGE,
        "Test",
        reset_at=now + timedelta(minutes=60),
    )
