"""Tradfri fan (recognised as air purifiers in the IKEA ecosystem) platform tests."""
from __future__ import annotations

from typing import Any
from unittest.mock import MagicMock, Mock

import pytest
from pytradfri.const import (
    ATTR_AIR_PURIFIER_FAN_SPEED,
    ATTR_AIR_PURIFIER_MODE,
    ATTR_REACHABLE_STATE,
    ROOT_AIR_PURIFIER,
)
from pytradfri.device.air_purifier import AirPurifier

from homeassistant.components.fan import (
    ATTR_PERCENTAGE,
    ATTR_PERCENTAGE_STEP,
    ATTR_PRESET_MODE,
    ATTR_PRESET_MODES,
    DOMAIN as FAN_DOMAIN,
    SERVICE_SET_PERCENTAGE,
    SERVICE_SET_PRESET_MODE,
    SERVICE_TURN_OFF,
    SERVICE_TURN_ON,
)
from homeassistant.const import (
    ATTR_SUPPORTED_FEATURES,
    STATE_OFF,
    STATE_ON,
    STATE_UNAVAILABLE,
)
from homeassistant.core import HomeAssistant

from .common import setup_integration, trigger_observe_callback


async def test_fan_available(
    hass: HomeAssistant,
    mock_gateway: Mock,
    mock_api_factory: MagicMock,
    air_purifier: AirPurifier,
) -> None:
    """Test fan available property."""
    entity_id = "fan.test"
    device = air_purifier.device
    mock_gateway.mock_devices.append(device)
    await setup_integration(hass)

    state = hass.states.get(entity_id)
    assert state
    assert state.state == STATE_OFF
    assert state.attributes[ATTR_PERCENTAGE] == 18
    assert state.attributes[ATTR_PERCENTAGE_STEP] == pytest.approx(2.040816)
    assert state.attributes[ATTR_PRESET_MODES] == ["Auto"]
    assert state.attributes[ATTR_PRESET_MODE] is None
    assert state.attributes[ATTR_SUPPORTED_FEATURES] == 9

    await trigger_observe_callback(
        hass, mock_gateway, device, {ATTR_REACHABLE_STATE: 0}
    )

    state = hass.states.get(entity_id)
    assert state
    assert state.state == STATE_UNAVAILABLE


@pytest.mark.parametrize(
    (
        "service",
        "service_data",
        "device_state",
        "expected_state",
        "expected_percentage",
        "expected_preset_mode",
    ),
    [
        (
            SERVICE_SET_PERCENTAGE,
            {ATTR_PERCENTAGE: 50},
            {
                ATTR_AIR_PURIFIER_FAN_SPEED: 25,
                ATTR_AIR_PURIFIER_MODE: 25,
            },
            STATE_ON,
            49,
            None,
        ),
        (
            SERVICE_SET_PERCENTAGE,
            {ATTR_PERCENTAGE: 0},
            {
                ATTR_AIR_PURIFIER_FAN_SPEED: 0,
                ATTR_AIR_PURIFIER_MODE: 0,
            },
            STATE_OFF,
            None,
            None,
        ),
        (
            SERVICE_TURN_ON,
            {ATTR_PERCENTAGE: 50},
            {
                ATTR_AIR_PURIFIER_FAN_SPEED: 25,
                ATTR_AIR_PURIFIER_MODE: 25,
            },
            STATE_ON,
            49,
            None,
        ),
        (
            SERVICE_TURN_ON,
            {ATTR_PRESET_MODE: "Auto"},
            {
                ATTR_AIR_PURIFIER_MODE: 1,
            },
            STATE_ON,
            18,
            "Auto",
        ),
        (
            SERVICE_TURN_ON,
            {},
            {
                ATTR_AIR_PURIFIER_MODE: 1,
            },
            STATE_ON,
            18,
            "Auto",
        ),
        (
            SERVICE_SET_PRESET_MODE,
            {ATTR_PRESET_MODE: "Auto"},
            {
                ATTR_AIR_PURIFIER_MODE: 1,
            },
            STATE_ON,
            18,
            "Auto",
        ),
        (
            SERVICE_TURN_OFF,
            {},
            {
                ATTR_AIR_PURIFIER_FAN_SPEED: 0,
                ATTR_AIR_PURIFIER_MODE: 0,
            },
            STATE_OFF,
            None,
            None,
        ),
    ],
)
async def test_services(
    hass: HomeAssistant,
    mock_gateway: Mock,
    mock_api_factory: MagicMock,
    air_purifier: AirPurifier,
    service: str,
    service_data: dict[str, Any],
    device_state: dict[str, Any],
    expected_state: str,
    expected_percentage: int | None,
    expected_preset_mode: str | None,
) -> None:
    """Test fan services."""
    entity_id = "fan.test"
    device = air_purifier.device
    mock_gateway.mock_devices.append(device)
    await setup_integration(hass)

    state = hass.states.get(entity_id)
    assert state
    assert state.state == STATE_OFF
    assert state.attributes[ATTR_PERCENTAGE] == 18
    assert state.attributes[ATTR_PERCENTAGE_STEP] == pytest.approx(2.040816)
    assert state.attributes[ATTR_PRESET_MODES] == ["Auto"]
    assert state.attributes[ATTR_PRESET_MODE] is None
    assert state.attributes[ATTR_SUPPORTED_FEATURES] == 9

    await hass.services.async_call(
        FAN_DOMAIN,
        service,
        {"entity_id": entity_id, **service_data},
        blocking=True,
    )
    await hass.async_block_till_done()

    await trigger_observe_callback(
        hass,
        mock_gateway,
        device,
        {ROOT_AIR_PURIFIER: [device_state]},
    )

    state = hass.states.get(entity_id)
    assert state
    assert state.state == expected_state
    assert state.attributes[ATTR_PERCENTAGE] == expected_percentage
    assert state.attributes[ATTR_PRESET_MODE] == expected_preset_mode