"""Test for the switchbot_cloud climate."""

from unittest.mock import patch

from switchbot_api import Device, Remote, SmartRadiatorThermostatCommands, SwitchBotAPI

from homeassistant.components.climate import (
    ATTR_FAN_MODE,
    ATTR_HVAC_MODE,
    ATTR_TEMPERATURE,
    DOMAIN as CLIMATE_DOMAIN,
    SERVICE_SET_FAN_MODE,
    SERVICE_SET_HVAC_MODE,
    SERVICE_SET_PRESET_MODE,
    SERVICE_SET_TEMPERATURE,
    SERVICE_TURN_OFF,
    SERVICE_TURN_ON,
    HVACMode,
)
from homeassistant.config_entries import ConfigEntryState
from homeassistant.const import ATTR_ENTITY_ID
from homeassistant.core import HomeAssistant, State

from . import configure_integration

from tests.common import mock_restore_cache


async def test_air_conditioner_set_hvac_mode(
    hass: HomeAssistant, mock_list_devices, mock_get_status
) -> None:
    """Test setting HVAC mode for air conditioner."""
    mock_list_devices.return_value = [
        Remote(
            deviceId="ac-device-id-1",
            deviceName="climate-1",
            remoteType="DIY Air Conditioner",
            hubDeviceId="test-hub-id",
        ),
    ]

    entry = await configure_integration(hass)
    assert entry.state is ConfigEntryState.LOADED

    entity_id = "climate.climate_1"

    with patch.object(SwitchBotAPI, "send_command") as mock_send_command:
        await hass.services.async_call(
            CLIMATE_DOMAIN,
            SERVICE_SET_HVAC_MODE,
            {ATTR_ENTITY_ID: entity_id, ATTR_HVAC_MODE: "cool"},
            blocking=True,
        )
        mock_send_command.assert_called_once()
        assert "21,2,1,on" in str(mock_send_command.call_args)

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

    # Test turning off
    with patch.object(SwitchBotAPI, "send_command") as mock_send_command:
        await hass.services.async_call(
            CLIMATE_DOMAIN,
            SERVICE_SET_HVAC_MODE,
            {ATTR_ENTITY_ID: entity_id, ATTR_HVAC_MODE: "off"},
            blocking=True,
        )
        mock_send_command.assert_called_once()
        assert "21,2,1,off" in str(mock_send_command.call_args)

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


async def test_air_conditioner_set_fan_mode(
    hass: HomeAssistant, mock_list_devices, mock_get_status
) -> None:
    """Test setting fan mode for air conditioner."""
    mock_list_devices.return_value = [
        Remote(
            deviceId="ac-device-id-1",
            deviceName="climate-1",
            remoteType="Air Conditioner",
            hubDeviceId="test-hub-id",
        ),
    ]

    entry = await configure_integration(hass)
    assert entry.state is ConfigEntryState.LOADED
    entity_id = "climate.climate_1"

    with patch.object(SwitchBotAPI, "send_command") as mock_send_command:
        await hass.services.async_call(
            CLIMATE_DOMAIN,
            SERVICE_SET_FAN_MODE,
            {ATTR_ENTITY_ID: entity_id, ATTR_FAN_MODE: "high"},
            blocking=True,
        )
        mock_send_command.assert_called_once()
        assert "21,4,4,on" in str(mock_send_command.call_args)

    assert hass.states.get(entity_id).attributes[ATTR_FAN_MODE] == "high"


async def test_air_conditioner_set_temperature(
    hass: HomeAssistant, mock_list_devices, mock_get_status
) -> None:
    """Test setting temperature for air conditioner."""
    mock_list_devices.return_value = [
        Remote(
            deviceId="ac-device-id-1",
            deviceName="climate-1",
            remoteType="Air Conditioner",
            hubDeviceId="test-hub-id",
        ),
    ]

    entry = await configure_integration(hass)
    assert entry.state is ConfigEntryState.LOADED
    entity_id = "climate.climate_1"

    with patch.object(SwitchBotAPI, "send_command") as mock_send_command:
        await hass.services.async_call(
            CLIMATE_DOMAIN,
            SERVICE_SET_TEMPERATURE,
            {ATTR_ENTITY_ID: entity_id, ATTR_TEMPERATURE: 25},
            blocking=True,
        )
        mock_send_command.assert_called_once()
        assert "25,4,1,on" in str(mock_send_command.call_args)

    assert hass.states.get(entity_id).attributes[ATTR_TEMPERATURE] == 25


async def test_air_conditioner_restore_state(
    hass: HomeAssistant, mock_list_devices, mock_get_status
) -> None:
    """Test restoring state for air conditioner."""
    mock_list_devices.return_value = [
        Remote(
            deviceId="ac-device-id-1",
            deviceName="climate-1",
            remoteType="Air Conditioner",
            hubDeviceId="test-hub-id",
        ),
    ]

    mock_state = State(
        "climate.climate_1",
        "cool",
        {
            ATTR_FAN_MODE: "high",
            ATTR_TEMPERATURE: 25,
        },
    )

    mock_restore_cache(hass, (mock_state,))
    entry = await configure_integration(hass)
    assert entry.state is ConfigEntryState.LOADED
    entity_id = "climate.climate_1"
    state = hass.states.get(entity_id)
    assert state.state == "cool"
    assert state.attributes[ATTR_FAN_MODE] == "high"
    assert state.attributes[ATTR_TEMPERATURE] == 25


async def test_air_conditioner_no_last_state(
    hass: HomeAssistant, mock_list_devices, mock_get_status
) -> None:
    """Test behavior when no previous state exists."""
    mock_list_devices.return_value = [
        Remote(
            deviceId="ac-device-id-1",
            deviceName="climate-1",
            remoteType="Air Conditioner",
            hubDeviceId="test-hub-id",
        ),
    ]

    entry = await configure_integration(hass)
    assert entry.state is ConfigEntryState.LOADED

    entity_id = "climate.climate_1"
    state = hass.states.get(entity_id)
    assert state.state == "fan_only"
    assert state.attributes[ATTR_FAN_MODE] == "auto"
    assert state.attributes[ATTR_TEMPERATURE] == 21


async def test_air_conditioner_turn_off(
    hass: HomeAssistant, mock_list_devices, mock_get_status
) -> None:
    """Test the climate.turn_off service."""
    mock_list_devices.return_value = [
        Remote(
            deviceId="ac-device-id-1",
            deviceName="climate-1",
            remoteType="DIY Air Conditioner",
            hubDeviceId="test-hub-id",
        ),
    ]

    entry = await configure_integration(hass)
    assert entry.state is ConfigEntryState.LOADED

    entity_id = "climate.climate_1"
    assert hass.states.get(entity_id).state == "fan_only"

    with patch.object(SwitchBotAPI, "send_command") as mock_send_command:
        await hass.services.async_call(
            CLIMATE_DOMAIN,
            SERVICE_TURN_OFF,
            {ATTR_ENTITY_ID: entity_id},
            blocking=True,
        )
        mock_send_command.assert_called_once()
        assert "21,4,1,off" in str(mock_send_command.call_args)

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


async def test_air_conditioner_turn_on(
    hass: HomeAssistant, mock_list_devices, mock_get_status
) -> None:
    """Test turning on a climate entity that has a non-off HVAC_STATE."""
    mock_list_devices.return_value = [
        Remote(
            deviceId="ac-device-id-1",
            deviceName="climate-1",
            remoteType="DIY Air Conditioner",
            hubDeviceId="test-hub-id",
        ),
    ]

    mock_state = State(
        "climate.climate_1",
        "cool",
        {
            ATTR_FAN_MODE: "high",
            ATTR_TEMPERATURE: 25,
        },
    )
    mock_restore_cache(hass, (mock_state,))
    entry = await configure_integration(hass)
    assert entry.state is ConfigEntryState.LOADED

    entity_id = "climate.climate_1"
    assert hass.states.get(entity_id).state == "cool"

    with patch.object(SwitchBotAPI, "send_command") as mock_turn_on_command:
        await hass.services.async_call(
            CLIMATE_DOMAIN,
            SERVICE_TURN_ON,
            {ATTR_ENTITY_ID: entity_id},
            blocking=True,
        )
        mock_turn_on_command.assert_called_once()
        assert "25,2,4,on" in str(mock_turn_on_command.call_args)

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


async def test_air_conditioner_turn_on_from_hvac_mode_off(
    hass: HomeAssistant, mock_list_devices, mock_get_status
) -> None:
    """Test turning on a climate entity that has an off HVAC_STATE."""
    mock_list_devices.return_value = [
        Remote(
            deviceId="ac-device-id-1",
            deviceName="climate-1",
            remoteType="DIY Air Conditioner",
            hubDeviceId="test-hub-id",
        ),
    ]

    mock_state = State(
        "climate.climate_1",
        "off",
        {
            ATTR_FAN_MODE: "high",
            ATTR_TEMPERATURE: 25,
        },
    )
    mock_restore_cache(hass, (mock_state,))
    entry = await configure_integration(hass)
    assert entry.state is ConfigEntryState.LOADED

    entity_id = "climate.climate_1"
    assert hass.states.get(entity_id).state == "off"

    with patch.object(SwitchBotAPI, "send_command") as mock_turn_on_command:
        await hass.services.async_call(
            CLIMATE_DOMAIN,
            SERVICE_TURN_ON,
            {ATTR_ENTITY_ID: entity_id},
            blocking=True,
        )
        mock_turn_on_command.assert_called_once()
        assert "25,4,4,on" in str(mock_turn_on_command.call_args)

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


async def test_smart_radiator_thermostat_set_temperature(
    hass: HomeAssistant, mock_list_devices, mock_get_status
) -> None:
    """Test smart radiator thermostat set temperature."""
    mock_list_devices.return_value = [
        Device(
            version="V1.0",
            deviceId="ac-device-id-1",
            deviceName="climate-1",
            deviceType="Smart Radiator Thermostat",
            hubDeviceId="test-hub-id",
        ),
    ]

    mock_get_status.side_effect = [
        {
            "mode": 1,
            "temperature": 27.5,
        },
        {
            "mode": 1,
            "temperature": 27.5,
        },
        {
            "mode": 2,
            "temperature": 27.5,
        },
    ]
    entry = await configure_integration(hass)
    assert entry.state is ConfigEntryState.LOADED

    entity_id = "climate.climate_1"

    with patch.object(SwitchBotAPI, "send_command") as mock_send_command:
        await hass.services.async_call(
            CLIMATE_DOMAIN,
            SERVICE_SET_TEMPERATURE,
            {ATTR_ENTITY_ID: entity_id, "temperature": 27},
        )
    mock_send_command.assert_called_once_with(
        "ac-device-id-1",
        SmartRadiatorThermostatCommands.SET_MANUAL_MODE_TEMPERATURE,
        "command",
        "27.0",
    )


async def test_smart_radiator_thermostat_set_preset_mode(
    hass: HomeAssistant, mock_list_devices, mock_get_status
) -> None:
    """Test smart radiator thermostat set preset mode."""
    mock_list_devices.return_value = [
        Device(
            version="V1.0",
            deviceId="ac-device-id-1",
            deviceName="climate-1",
            deviceType="Smart Radiator Thermostat",
            hubDeviceId="test-hub-id",
        ),
    ]

    mock_get_status.side_effect = [
        {
            "mode": 1,
            "temperature": 27.5,
        },
        {
            "mode": 1,
            "temperature": 27.5,
        },
        {
            "mode": 2,
            "temperature": 27.5,
        },
    ]
    entry = await configure_integration(hass)
    assert entry.state is ConfigEntryState.LOADED

    entity_id = "climate.climate_1"

    with patch.object(SwitchBotAPI, "send_command") as mock_send_command:
        await hass.services.async_call(
            CLIMATE_DOMAIN,
            SERVICE_SET_PRESET_MODE,
            {ATTR_ENTITY_ID: entity_id, "preset_mode": "none"},
        )
    mock_send_command.assert_called_once_with(
        "ac-device-id-1",
        SmartRadiatorThermostatCommands.SET_MODE,
        "command",
        2,
    )

    with patch.object(SwitchBotAPI, "send_command") as mock_send_command:
        await hass.services.async_call(
            CLIMATE_DOMAIN,
            SERVICE_SET_PRESET_MODE,
            {ATTR_ENTITY_ID: entity_id, "preset_mode": "home"},
        )
    mock_send_command.assert_called_once_with(
        "ac-device-id-1",
        SmartRadiatorThermostatCommands.SET_MODE,
        "command",
        1,
    )


async def test_smart_radiator_thermostat_set_hvac_mode(
    hass: HomeAssistant, mock_list_devices, mock_get_status
) -> None:
    """Test smart radiator thermostat set hvac mode."""
    mock_list_devices.return_value = [
        Device(
            version="V1.0",
            deviceId="ac-device-id-1",
            deviceName="climate-1",
            deviceType="Smart Radiator Thermostat",
            hubDeviceId="test-hub-id",
        ),
    ]

    mock_get_status.side_effect = [
        {
            "mode": 2,
            "temperature": 27.5,
        },
        {
            "mode": 2,
            "temperature": 27.5,
        },
        {
            "mode": 2,
            "temperature": 27.5,
        },
    ]
    entry = await configure_integration(hass)
    assert entry.state is ConfigEntryState.LOADED

    entity_id = "climate.climate_1"

    with patch.object(SwitchBotAPI, "send_command") as mock_send_command:
        await hass.services.async_call(
            CLIMATE_DOMAIN,
            SERVICE_SET_HVAC_MODE,
            {ATTR_ENTITY_ID: entity_id, "hvac_mode": HVACMode.OFF},
        )
    mock_send_command.assert_called_once_with(
        "ac-device-id-1",
        SmartRadiatorThermostatCommands.SET_MODE,
        "command",
        2,
    )

    with patch.object(SwitchBotAPI, "send_command") as mock_send_command:
        await hass.services.async_call(
            CLIMATE_DOMAIN,
            SERVICE_SET_HVAC_MODE,
            {ATTR_ENTITY_ID: entity_id, "hvac_mode": HVACMode.HEAT},
        )
    mock_send_command.assert_called_once_with(
        "ac-device-id-1",
        SmartRadiatorThermostatCommands.SET_MODE,
        "command",
        5,
    )
