"""Test IntelliClima Select."""

from collections.abc import AsyncGenerator
from unittest.mock import AsyncMock, patch

from pyintelliclima.const import FanMode, FanSpeed
import pytest
from syrupy.assertion import SnapshotAssertion

from homeassistant.components.select import (
    ATTR_OPTION,
    DOMAIN as SELECT_DOMAIN,
    SERVICE_SELECT_OPTION,
)
from homeassistant.const import ATTR_ENTITY_ID, Platform
from homeassistant.core import HomeAssistant
from homeassistant.helpers import device_registry as dr, entity_registry as er

from . import setup_integration

from tests.common import MockConfigEntry, snapshot_platform

SELECT_ENTITY_ID = "select.test_vmc_fan_direction_mode"


@pytest.fixture(autouse=True)
async def setup_intelliclima_select_only(
    hass: HomeAssistant,
    mock_config_entry: MockConfigEntry,
    mock_cloud_interface: AsyncMock,
) -> AsyncGenerator[None]:
    """Set up IntelliClima integration with only the select platform."""
    with (
        patch("homeassistant.components.intelliclima.PLATFORMS", [Platform.SELECT]),
    ):
        await setup_integration(hass, mock_config_entry)
        # Let tests run against this initialized state
        yield


async def test_all_select_entities(
    hass: HomeAssistant,
    snapshot: SnapshotAssertion,
    mock_config_entry: MockConfigEntry,
    entity_registry: er.EntityRegistry,
    device_registry: dr.DeviceRegistry,
    mock_cloud_interface: AsyncMock,
) -> None:
    """Test all entities."""

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

    # There should be exactly one select entity
    select_entries = [
        entry
        for entry in entity_registry.entities.values()
        if entry.platform == "intelliclima" and entry.domain == SELECT_DOMAIN
    ]
    assert len(select_entries) == 1

    entity_entry = select_entries[0]
    assert entity_entry.device_id
    assert (device_entry := device_registry.async_get(entity_entry.device_id))
    assert device_entry == snapshot


@pytest.mark.parametrize(
    ("option", "expected_mode"),
    [
        ("forward", FanMode.inward),
        ("reverse", FanMode.outward),
        ("alternate", FanMode.alternate),
        ("sensor", FanMode.sensor),
    ],
)
async def test_select_option_keeps_current_speed(
    hass: HomeAssistant,
    mock_cloud_interface: AsyncMock,
    option: str,
    expected_mode: FanMode,
) -> None:
    """Selecting any valid option retains the current speed and calls set_mode_speed."""
    await hass.services.async_call(
        SELECT_DOMAIN,
        SERVICE_SELECT_OPTION,
        {ATTR_ENTITY_ID: SELECT_ENTITY_ID, ATTR_OPTION: option},
        blocking=True,
    )
    # Device starts with speed_set=FanSpeed.medium (from single_eco_device in conftest),
    # mode is not off and not auto, so current speed is preserved.
    mock_cloud_interface.ecocomfort.set_mode_speed.assert_awaited_once_with(
        "11223344", expected_mode, FanSpeed.medium
    )


async def test_select_option_when_off_defaults_speed_to_sleep(
    hass: HomeAssistant,
    mock_cloud_interface: AsyncMock,
    single_eco_device,
) -> None:
    """Test selecting option when off defaults speed to sleep."""
    # Mutate the shared fixture object – coordinator.data points to the same reference.
    eco = list(single_eco_device.ecocomfort2_devices.values())[0]
    eco.mode_set = FanMode.off

    await hass.services.async_call(
        SELECT_DOMAIN,
        SERVICE_SELECT_OPTION,
        {ATTR_ENTITY_ID: SELECT_ENTITY_ID, ATTR_OPTION: "forward"},
        blocking=True,
    )
    mock_cloud_interface.ecocomfort.set_mode_speed.assert_awaited_once_with(
        "11223344", FanMode.inward, FanSpeed.sleep
    )


async def test_select_option_in_auto_mode_defaults_speed_to_sleep(
    hass: HomeAssistant,
    mock_cloud_interface: AsyncMock,
    single_eco_device,
) -> None:
    """Test selecting option in auto preset defaults to sleep speed."""
    eco = list(single_eco_device.ecocomfort2_devices.values())[0]
    eco.speed_set = FanSpeed.auto_get
    eco.mode_set = FanMode.sensor

    await hass.services.async_call(
        SELECT_DOMAIN,
        SERVICE_SELECT_OPTION,
        {ATTR_ENTITY_ID: SELECT_ENTITY_ID, ATTR_OPTION: "reverse"},
        blocking=True,
    )
    mock_cloud_interface.ecocomfort.set_mode_speed.assert_awaited_once_with(
        "11223344", FanMode.outward, FanSpeed.sleep
    )


@pytest.mark.parametrize("option", ["forward", "reverse", "alternate", "sensor"])
async def test_select_option_does_not_call_turn_off(
    hass: HomeAssistant,
    mock_cloud_interface: AsyncMock,
    option: str,
) -> None:
    """Selecting an option should never call turn_off."""
    await hass.services.async_call(
        SELECT_DOMAIN,
        SERVICE_SELECT_OPTION,
        {ATTR_ENTITY_ID: SELECT_ENTITY_ID, ATTR_OPTION: option},
        blocking=True,
    )
    mock_cloud_interface.ecocomfort.turn_off.assert_not_awaited()


async def test_select_option_triggers_coordinator_refresh(
    hass: HomeAssistant,
    mock_cloud_interface: AsyncMock,
) -> None:
    """Selecting an option should trigger a coordinator refresh after the API call."""
    initial_call_count = mock_cloud_interface.get_all_device_status.call_count

    await hass.services.async_call(
        SELECT_DOMAIN,
        SERVICE_SELECT_OPTION,
        {ATTR_ENTITY_ID: SELECT_ENTITY_ID, ATTR_OPTION: "sensor"},
        blocking=True,
    )
    # A refresh must have been requested, so the status fetch count increases.
    assert mock_cloud_interface.get_all_device_status.call_count > initial_call_count
