"""Support for Rheem EcoNet thermostats."""
from pyeconet.equipment import EquipmentType
from pyeconet.equipment.thermostat import ThermostatFanMode, ThermostatOperationMode

from homeassistant.components.climate import ClimateEntity
from homeassistant.components.climate.const import (
    ATTR_TARGET_TEMP_HIGH,
    ATTR_TARGET_TEMP_LOW,
    FAN_AUTO,
    FAN_HIGH,
    FAN_LOW,
    FAN_MEDIUM,
    HVAC_MODE_COOL,
    HVAC_MODE_FAN_ONLY,
    HVAC_MODE_HEAT,
    HVAC_MODE_HEAT_COOL,
    HVAC_MODE_OFF,
    SUPPORT_AUX_HEAT,
    SUPPORT_FAN_MODE,
    SUPPORT_TARGET_HUMIDITY,
    SUPPORT_TARGET_TEMPERATURE,
    SUPPORT_TARGET_TEMPERATURE_RANGE,
)
from homeassistant.config_entries import ConfigEntry
from homeassistant.const import ATTR_TEMPERATURE
from homeassistant.core import HomeAssistant
from homeassistant.helpers.entity_platform import AddEntitiesCallback

from . import EcoNetEntity
from .const import DOMAIN, EQUIPMENT

ECONET_STATE_TO_HA = {
    ThermostatOperationMode.HEATING: HVAC_MODE_HEAT,
    ThermostatOperationMode.COOLING: HVAC_MODE_COOL,
    ThermostatOperationMode.OFF: HVAC_MODE_OFF,
    ThermostatOperationMode.AUTO: HVAC_MODE_HEAT_COOL,
    ThermostatOperationMode.FAN_ONLY: HVAC_MODE_FAN_ONLY,
}
HA_STATE_TO_ECONET = {value: key for key, value in ECONET_STATE_TO_HA.items()}

ECONET_FAN_STATE_TO_HA = {
    ThermostatFanMode.AUTO: FAN_AUTO,
    ThermostatFanMode.LOW: FAN_LOW,
    ThermostatFanMode.MEDIUM: FAN_MEDIUM,
    ThermostatFanMode.HIGH: FAN_HIGH,
}
HA_FAN_STATE_TO_ECONET = {value: key for key, value in ECONET_FAN_STATE_TO_HA.items()}

SUPPORT_FLAGS_THERMOSTAT = (
    SUPPORT_TARGET_TEMPERATURE
    | SUPPORT_TARGET_TEMPERATURE_RANGE
    | SUPPORT_FAN_MODE
    | SUPPORT_AUX_HEAT
)


async def async_setup_entry(
    hass: HomeAssistant, entry: ConfigEntry, async_add_entities: AddEntitiesCallback
) -> None:
    """Set up EcoNet thermostat based on a config entry."""
    equipment = hass.data[DOMAIN][EQUIPMENT][entry.entry_id]
    async_add_entities(
        [
            EcoNetThermostat(thermostat)
            for thermostat in equipment[EquipmentType.THERMOSTAT]
        ],
    )


class EcoNetThermostat(EcoNetEntity, ClimateEntity):
    """Define a Econet thermostat."""

    def __init__(self, thermostat):
        """Initialize."""
        super().__init__(thermostat)
        self._running = thermostat.running
        self._poll = True
        self.econet_state_to_ha = {}
        self.ha_state_to_econet = {}
        self.op_list = []
        for mode in self._econet.modes:
            if mode not in [
                ThermostatOperationMode.UNKNOWN,
                ThermostatOperationMode.EMERGENCY_HEAT,
            ]:
                ha_mode = ECONET_STATE_TO_HA[mode]
                self.op_list.append(ha_mode)

    @property
    def supported_features(self):
        """Return the list of supported features."""
        if self._econet.supports_humidifier:
            return SUPPORT_FLAGS_THERMOSTAT | SUPPORT_TARGET_HUMIDITY
        return SUPPORT_FLAGS_THERMOSTAT

    @property
    def current_temperature(self):
        """Return the current temperature."""
        return self._econet.set_point

    @property
    def current_humidity(self):
        """Return the current humidity."""
        return self._econet.humidity

    @property
    def target_humidity(self):
        """Return the humidity we try to reach."""
        if self._econet.supports_humidifier:
            return self._econet.dehumidifier_set_point
        return None

    @property
    def target_temperature(self):
        """Return the temperature we try to reach."""
        if self.hvac_mode == HVAC_MODE_COOL:
            return self._econet.cool_set_point
        if self.hvac_mode == HVAC_MODE_HEAT:
            return self._econet.heat_set_point
        return None

    @property
    def target_temperature_low(self):
        """Return the lower bound temperature we try to reach."""
        if self.hvac_mode == HVAC_MODE_HEAT_COOL:
            return self._econet.heat_set_point
        return None

    @property
    def target_temperature_high(self):
        """Return the higher bound temperature we try to reach."""
        if self.hvac_mode == HVAC_MODE_HEAT_COOL:
            return self._econet.cool_set_point
        return None

    def set_temperature(self, **kwargs):
        """Set new target temperature."""
        target_temp = kwargs.get(ATTR_TEMPERATURE)
        target_temp_low = kwargs.get(ATTR_TARGET_TEMP_LOW)
        target_temp_high = kwargs.get(ATTR_TARGET_TEMP_HIGH)
        if target_temp:
            self._econet.set_set_point(target_temp, None, None)
        if target_temp_low or target_temp_high:
            self._econet.set_set_point(None, target_temp_high, target_temp_low)

    @property
    def is_aux_heat(self):
        """Return true if aux heater."""
        return self._econet.mode == ThermostatOperationMode.EMERGENCY_HEAT

    @property
    def hvac_modes(self):
        """Return hvac operation ie. heat, cool mode.

        Needs to be one of HVAC_MODE_*.
        """
        return self.op_list

    @property
    def hvac_mode(self) -> str:
        """Return hvac operation ie. heat, cool, mode.

        Needs to be one of HVAC_MODE_*.
        """
        econet_mode = self._econet.mode
        _current_op = HVAC_MODE_OFF
        if econet_mode is not None:
            _current_op = ECONET_STATE_TO_HA[econet_mode]

        return _current_op

    def set_hvac_mode(self, hvac_mode):
        """Set new target hvac mode."""
        hvac_mode_to_set = HA_STATE_TO_ECONET.get(hvac_mode)
        if hvac_mode_to_set is None:
            raise ValueError(f"{hvac_mode} is not a valid mode.")
        self._econet.set_mode(hvac_mode_to_set)

    def set_humidity(self, humidity: int):
        """Set new target humidity."""
        self._econet.set_dehumidifier_set_point(humidity)

    @property
    def fan_mode(self):
        """Return the current fan mode."""
        econet_fan_mode = self._econet.fan_mode

        # Remove this after we figure out how to handle med lo and med hi
        if econet_fan_mode in [ThermostatFanMode.MEDHI, ThermostatFanMode.MEDLO]:
            econet_fan_mode = ThermostatFanMode.MEDIUM

        _current_fan_mode = FAN_AUTO
        if econet_fan_mode is not None:
            _current_fan_mode = ECONET_FAN_STATE_TO_HA[econet_fan_mode]
        return _current_fan_mode

    @property
    def fan_modes(self):
        """Return the fan modes."""
        econet_fan_modes = self._econet.fan_modes
        fan_list = []
        for mode in econet_fan_modes:
            # Remove the MEDLO MEDHI once we figure out how to handle it
            if mode not in [
                ThermostatFanMode.UNKNOWN,
                ThermostatFanMode.MEDLO,
                ThermostatFanMode.MEDHI,
            ]:
                fan_list.append(ECONET_FAN_STATE_TO_HA[mode])
        return fan_list

    def set_fan_mode(self, fan_mode):
        """Set the fan mode."""
        self._econet.set_fan_mode(HA_FAN_STATE_TO_ECONET[fan_mode])

    def turn_aux_heat_on(self):
        """Turn auxiliary heater on."""
        self._econet.set_mode(ThermostatOperationMode.EMERGENCY_HEAT)

    def turn_aux_heat_off(self):
        """Turn auxiliary heater off."""
        self._econet.set_mode(ThermostatOperationMode.HEATING)

    @property
    def min_temp(self):
        """Return the minimum temperature."""
        return self._econet.set_point_limits[0]

    @property
    def max_temp(self):
        """Return the maximum temperature."""
        return self._econet.set_point_limits[1]

    @property
    def min_humidity(self) -> int:
        """Return the minimum humidity."""
        return self._econet.dehumidifier_set_point_limits[0]

    @property
    def max_humidity(self) -> int:
        """Return the maximum humidity."""
        return self._econet.dehumidifier_set_point_limits[1]
