# pylint: disable=wildcard-import, unused-wildcard-import, protected-access, unused-argument, line-too-long

""" Test the auto fan mode of a over_climate thermostat """
from unittest.mock import patch, call

from datetime import datetime  # , timedelta

from homeassistant.core import HomeAssistant

# from homeassistant.components.climate import HVACAction, HVACMode
from homeassistant.config_entries import ConfigEntryState

# from homeassistant.helpers.entity_component import EntityComponent
# from homeassistant.components.climate import ClimateEntity, DOMAIN as CLIMATE_DOMAIN

from pytest_homeassistant_custom_component.common import MockConfigEntry

# from custom_components.versatile_thermostat.base_thermostat import BaseThermostat
from custom_components.versatile_thermostat.thermostat_climate import (
    ThermostatOverClimate,
)

from .commons import *  # pylint: disable=wildcard-import, unused-wildcard-import


@pytest.mark.parametrize("expected_lingering_tasks", [True])
@pytest.mark.parametrize("expected_lingering_timers", [True])
async def test_over_climate_auto_fan_mode_turbo(
    hass: HomeAssistant, skip_hass_states_is_state, skip_send_event
):
    """Test the init of an over climate thermostat with auto_fan_mode = Turbo which exists"""

    fan_modes = ["low", "medium", "high", "boost", "mute", "auto", "turbo"]

    entry = MockConfigEntry(
        domain=DOMAIN,
        title="TheOverClimateMockName",
        unique_id="uniqueId",
        data={
            CONF_NAME: "TheOverClimateMockName",
            CONF_THERMOSTAT_TYPE: CONF_THERMOSTAT_CLIMATE,
            CONF_TEMP_SENSOR: "sensor.mock_temp_sensor",
            CONF_EXTERNAL_TEMP_SENSOR: "sensor.mock_ext_temp_sensor",
            CONF_CYCLE_MIN: 5,
            CONF_TEMP_MIN: 15,
            CONF_TEMP_MAX: 30,
            "eco_temp": 17,
            "comfort_temp": 18,
            "boost_temp": 19,
            CONF_USE_WINDOW_FEATURE: False,
            CONF_USE_MOTION_FEATURE: False,
            CONF_USE_POWER_FEATURE: False,
            CONF_USE_PRESENCE_FEATURE: False,
            CONF_CLIMATE: "climate.mock_climate",
            CONF_MINIMAL_ACTIVATION_DELAY: 30,
            CONF_SECURITY_DELAY_MIN: 5,
            CONF_SECURITY_MIN_ON_PERCENT: 0.3,
            CONF_AUTO_FAN_MODE: CONF_AUTO_FAN_TURBO,
        },
    )

    fake_underlying_climate = MockClimate(
        hass=hass,
        unique_id="mockUniqueId",
        name="MockClimateName",
        fan_modes=fan_modes,
    )

    with patch(
        "custom_components.versatile_thermostat.underlyings.UnderlyingClimate.find_underlying_climate",
        return_value=fake_underlying_climate,
    ):
        entry.add_to_hass(hass)
        await hass.config_entries.async_setup(entry.entry_id)
        assert entry.state is ConfigEntryState.LOADED

        entity: ThermostatOverClimate = search_entity(
            hass, "climate.theoverclimatemockname", "climate"
        )

        assert entity
        assert isinstance(entity, ThermostatOverClimate)

        assert entity.name == "TheOverClimateMockName"
        assert entity.is_over_climate is True
        assert entity.fan_modes == fan_modes
        assert entity._auto_fan_mode == "auto_fan_turbo"
        assert entity._auto_activated_fan_mode == "turbo"
        assert entity._auto_deactivated_fan_mode == "mute"


@pytest.mark.parametrize("expected_lingering_tasks", [True])
@pytest.mark.parametrize("expected_lingering_timers", [True])
async def test_over_climate_auto_fan_mode_not_turbo(
    hass: HomeAssistant, skip_hass_states_is_state, skip_send_event
):
    """Test the init of an over climate thermostat with auto_fan_mode = Turbo which doesn't exists"""

    fan_modes = ["low", "medium", "high", "boost", "auto"]

    entry = MockConfigEntry(
        domain=DOMAIN,
        title="TheOverClimateMockName",
        unique_id="uniqueId",
        data={
            CONF_NAME: "TheOverClimateMockName",
            CONF_THERMOSTAT_TYPE: CONF_THERMOSTAT_CLIMATE,
            CONF_TEMP_SENSOR: "sensor.mock_temp_sensor",
            CONF_EXTERNAL_TEMP_SENSOR: "sensor.mock_ext_temp_sensor",
            CONF_CYCLE_MIN: 5,
            CONF_TEMP_MIN: 15,
            CONF_TEMP_MAX: 30,
            "eco_temp": 17,
            "comfort_temp": 18,
            "boost_temp": 19,
            CONF_USE_WINDOW_FEATURE: False,
            CONF_USE_MOTION_FEATURE: False,
            CONF_USE_POWER_FEATURE: False,
            CONF_USE_PRESENCE_FEATURE: False,
            CONF_CLIMATE: "climate.mock_climate",
            CONF_MINIMAL_ACTIVATION_DELAY: 30,
            CONF_SECURITY_DELAY_MIN: 5,
            CONF_SECURITY_MIN_ON_PERCENT: 0.3,
            CONF_AUTO_FAN_MODE: CONF_AUTO_FAN_TURBO,
        },
    )

    fake_underlying_climate = MockClimate(
        hass=hass,
        unique_id="mockUniqueId",
        name="MockClimateName",
        fan_modes=fan_modes,
    )

    with patch(
        "custom_components.versatile_thermostat.underlyings.UnderlyingClimate.find_underlying_climate",
        return_value=fake_underlying_climate,
    ):
        entry.add_to_hass(hass)
        await hass.config_entries.async_setup(entry.entry_id)
        assert entry.state is ConfigEntryState.LOADED

        entity: ThermostatOverClimate = search_entity(
            hass, "climate.theoverclimatemockname", "climate"
        )

        assert entity
        assert isinstance(entity, ThermostatOverClimate)

        assert entity.name == "TheOverClimateMockName"
        assert entity.is_over_climate is True
        assert entity.fan_modes == fan_modes
        assert entity._auto_fan_mode == "auto_fan_turbo"
        # Turbo doesn't exists -> fallback to high
        assert entity._auto_activated_fan_mode == "high"
        # Mute doesn't exists -> fallback to auto
        assert entity._auto_deactivated_fan_mode == "auto"


@pytest.mark.parametrize("expected_lingering_timers", [True])
async def test_over_climate_auto_fan_mode_turbo_activation(
    hass: HomeAssistant, skip_hass_states_is_state, skip_send_event
):
    """Test the init of an over climate thermostat with auto_fan_mode = Turbo which exists"""

    fan_modes = ["low", "medium", "high", "boost", "mute", "auto", "turbo"]

    entry = MockConfigEntry(
        domain=DOMAIN,
        title="TheOverClimateMockName",
        unique_id="uniqueId",
        data={
            CONF_NAME: "TheOverClimateMockName",
            CONF_THERMOSTAT_TYPE: CONF_THERMOSTAT_CLIMATE,
            CONF_TEMP_SENSOR: "sensor.mock_temp_sensor",
            CONF_EXTERNAL_TEMP_SENSOR: "sensor.mock_ext_temp_sensor",
            CONF_CYCLE_MIN: 5,
            CONF_TEMP_MIN: 15,
            CONF_TEMP_MAX: 30,
            "eco_temp": 17,
            "comfort_temp": 18,
            "boost_temp": 19,
            "eco_ac_temp": 25,
            "comfort_ac_temp": 23,
            "boost_ac_temp": 21,
            CONF_USE_WINDOW_FEATURE: False,
            CONF_USE_MOTION_FEATURE: False,
            CONF_USE_POWER_FEATURE: False,
            CONF_USE_PRESENCE_FEATURE: False,
            CONF_CLIMATE: "climate.mock_climate",
            CONF_MINIMAL_ACTIVATION_DELAY: 30,
            CONF_SECURITY_DELAY_MIN: 5,
            CONF_SECURITY_MIN_ON_PERCENT: 0.3,
            CONF_AUTO_FAN_MODE: CONF_AUTO_FAN_TURBO,
            CONF_AC_MODE: True,
        },
    )

    tz = get_tz(hass)  # pylint: disable=invalid-name
    now: datetime = datetime.now(tz=tz)

    fake_underlying_climate = MockClimate(
        hass=hass,
        unique_id="mockUniqueId",
        name="MockClimateName",
        fan_modes=fan_modes,
    )

    # 1. Init fan mode
    with patch(
        "custom_components.versatile_thermostat.underlyings.UnderlyingClimate.find_underlying_climate",
        return_value=fake_underlying_climate,
    ):
        entry.add_to_hass(hass)
        await hass.config_entries.async_setup(entry.entry_id)
        assert entry.state is ConfigEntryState.LOADED

        entity: ThermostatOverClimate = search_entity(
            hass, "climate.theoverclimatemockname", "climate"
        )

        assert entity
        assert isinstance(entity, ThermostatOverClimate)

        assert entity.name == "TheOverClimateMockName"
        assert entity.is_over_climate is True
        assert entity.fan_modes == fan_modes
        assert entity.fan_mode is None
        assert entity._auto_fan_mode == "auto_fan_turbo"
        assert entity._auto_activated_fan_mode == "turbo"
        assert entity._auto_deactivated_fan_mode == "mute"

    # 2. Turn on and set temperature cold
    with patch(
        "custom_components.versatile_thermostat.underlyings.UnderlyingClimate.set_fan_mode"
    ) as mock_send_fan_mode:
        # Force preset mode
        await entity.async_set_hvac_mode(HVACMode.HEAT)
        assert entity.hvac_mode == HVACMode.HEAT
        await entity.async_set_preset_mode(PRESET_COMFORT)
        assert entity.preset_mode == PRESET_COMFORT
        assert entity.target_temperature == 18

        # Change the current temperature to 16 which is 2° under
        await send_temperature_change_event(entity, 16, now, True)
        fake_underlying_climate.set_fan_mode("turbo")

        assert mock_send_fan_mode.call_count == 1
        mock_send_fan_mode.assert_has_calls([call.set_fan_mode("turbo")])

        assert entity.fan_mode == "turbo"

    # 3. Set another low temperature
    with patch(
        "custom_components.versatile_thermostat.underlyings.UnderlyingClimate.set_fan_mode"
    ) as mock_send_fan_mode:
        fake_underlying_climate.set_fan_mode("turbo")

        # Change the current temperature to 17 which is 1° under
        await send_temperature_change_event(entity, 15, now, True)

        # Nothing is send cause we are already in turbo fan mode
        assert mock_send_fan_mode.call_count == 0

        assert entity.fan_mode == "turbo"

    # 4. Set temperature not so cold
    with patch(
        "custom_components.versatile_thermostat.underlyings.UnderlyingClimate.set_fan_mode"
    ) as mock_send_fan_mode:
        # Change the current temperature to 17 which is 1° under
        await send_temperature_change_event(entity, 17, now, True)
        fake_underlying_climate.set_fan_mode("mute")

        assert mock_send_fan_mode.call_count == 1
        mock_send_fan_mode.assert_has_calls([call.set_fan_mode("mute")])

        assert entity.fan_mode == "mute"

    # 5. Set temperature not so cold another time
    with patch(
        "custom_components.versatile_thermostat.underlyings.UnderlyingClimate.set_fan_mode"
    ) as mock_send_fan_mode:
        fake_underlying_climate.set_fan_mode("mute")

        # Change the current temperature to 17 which is 1° under
        await send_temperature_change_event(entity, 17.1, now, True)

        assert mock_send_fan_mode.call_count == 0
        assert entity.fan_mode == "mute"

    # 6. Set temperature very high above the target
    with patch(
        "custom_components.versatile_thermostat.underlyings.UnderlyingClimate.set_fan_mode"
    ) as mock_send_fan_mode:
        fake_underlying_climate.set_fan_mode("mute")

        # Change the current temperature to 17 which is 1° under
        await send_temperature_change_event(entity, 21, now, True)

        assert mock_send_fan_mode.call_count == 0
        assert entity.fan_mode == "mute"

    # 7. In AC mode, set temperature very high under the target
    with patch(
        "custom_components.versatile_thermostat.underlyings.UnderlyingClimate.set_fan_mode"
    ) as mock_send_fan_mode:
        await entity.async_set_hvac_mode(HVACMode.COOL)
        assert entity.hvac_mode == HVACMode.COOL
        assert entity.preset_mode == PRESET_COMFORT
        assert entity.target_temperature == 23

        assert entity.current_temperature == 21

        fake_underlying_climate.set_fan_mode("mute")

        # Change the current temperature to 17 which is 1° under
        await send_temperature_change_event(entity, 20, now, True)

        assert mock_send_fan_mode.call_count == 0
        assert entity.fan_mode == "mute"

    # 8. In AC mode, set temperature not so high above the target
    with patch(
        "custom_components.versatile_thermostat.underlyings.UnderlyingClimate.set_fan_mode"
    ) as mock_send_fan_mode:
        assert entity.target_temperature == 23
        await send_temperature_change_event(entity, 24, now, True)
        assert entity.current_temperature == 24
        fake_underlying_climate.set_fan_mode("mute")

        assert mock_send_fan_mode.call_count == 0
        assert entity.fan_mode == "mute"

    # 8. In AC mode, set temperature high above the target
    with patch(
        "custom_components.versatile_thermostat.underlyings.UnderlyingClimate.set_fan_mode"
    ) as mock_send_fan_mode:
        assert entity.target_temperature == 23
        await send_temperature_change_event(entity, 25.1, now, True)
        assert entity.current_temperature == 25.1
        fake_underlying_climate.set_fan_mode("turbo")

        assert mock_send_fan_mode.call_count == 1
        mock_send_fan_mode.assert_has_calls([call.set_fan_mode("turbo")])
        assert entity.fan_mode == "turbo"
