"""Support for waterheater entities."""

import logging
from typing import Any, override

from thinqconnect import DeviceType
from thinqconnect.integration import ExtendedProperty

from homeassistant.components.water_heater import (
    ATTR_OPERATION_MODE,
    STATE_ECO,
    STATE_HEAT_PUMP,
    STATE_OFF,
    STATE_PERFORMANCE,
    WaterHeaterEntity,
    WaterHeaterEntityDescription,
    WaterHeaterEntityFeature,
)
from homeassistant.const import ATTR_TEMPERATURE, UnitOfTemperature
from homeassistant.core import HomeAssistant
from homeassistant.helpers.entity_platform import AddConfigEntryEntitiesCallback

from . import ThinqConfigEntry
from .coordinator import DeviceDataUpdateCoordinator
from .entity import ThinQEntity

DEVICE_TYPE_WH_MAP: dict[DeviceType, WaterHeaterEntityDescription] = {
    DeviceType.WATER_HEATER: WaterHeaterEntityDescription(
        key=ExtendedProperty.WATER_HEATER,
        name=None,
    ),
    DeviceType.SYSTEM_BOILER: WaterHeaterEntityDescription(
        key=ExtendedProperty.WATER_BOILER,
        name=None,
    ),
}

# Mapping between device and HA operation modes
DEVICE_OP_MODE_TO_HA = {
    "auto": STATE_ECO,
    "heat_pump": STATE_HEAT_PUMP,
    "turbo": STATE_PERFORMANCE,
}
HA_STATE_TO_DEVICE_OP_MODE = {v: k for k, v in DEVICE_OP_MODE_TO_HA.items()}

_LOGGER = logging.getLogger(__name__)


async def async_setup_entry(
    hass: HomeAssistant,
    entry: ThinqConfigEntry,
    async_add_entities: AddConfigEntryEntitiesCallback,
) -> None:
    """Set up an entry for water_heater platform."""
    entities: list[ThinQWaterHeaterEntity] = []
    for coordinator in entry.runtime_data.coordinators.values():
        if (
            description := DEVICE_TYPE_WH_MAP.get(coordinator.api.device.device_type)
        ) is not None:
            if coordinator.api.device.device_type == DeviceType.WATER_HEATER:
                entities.append(
                    ThinQWaterHeaterEntity(
                        coordinator, description, ExtendedProperty.WATER_HEATER
                    )
                )
            elif coordinator.api.device.device_type == DeviceType.SYSTEM_BOILER:
                entities.append(
                    ThinQWaterBoilerEntity(
                        coordinator, description, ExtendedProperty.WATER_BOILER
                    )
                )
    if entities:
        async_add_entities(entities)


class ThinQWaterHeaterEntity(ThinQEntity, WaterHeaterEntity):
    """Represent a ThinQ water heater entity."""

    def __init__(
        self,
        coordinator: DeviceDataUpdateCoordinator,
        entity_description: WaterHeaterEntityDescription,
        property_id: str,
    ) -> None:
        """Initialize a water_heater entity."""
        super().__init__(coordinator, entity_description, property_id)
        self._attr_supported_features = (
            WaterHeaterEntityFeature.TARGET_TEMPERATURE
            | WaterHeaterEntityFeature.OPERATION_MODE
        )
        self._attr_temperature_unit = (
            self._get_unit_of_measurement(self.data.unit) or UnitOfTemperature.CELSIUS
        )
        if modes := self.data.job_modes:
            self._attr_operation_list = [
                DEVICE_OP_MODE_TO_HA.get(mode, mode) for mode in modes
            ]

    @override
    def _update_status(self) -> None:
        """Update status itself."""
        super()._update_status()
        self._attr_current_temperature = self.data.current_temp
        self._attr_target_temperature = self.data.target_temp

        if self.data.max is not None:
            self._attr_max_temp = self.data.max
        if self.data.min is not None:
            self._attr_min_temp = self.data.min
        if self.data.step is not None:
            self._attr_target_temperature_step = self.data.step

        self._attr_temperature_unit = (
            self._get_unit_of_measurement(self.data.unit) or UnitOfTemperature.CELSIUS
        )
        if self.data.is_on:
            self._attr_current_operation = (
                DEVICE_OP_MODE_TO_HA.get(job_mode, job_mode)
                if (job_mode := self.data.job_mode) is not None
                else STATE_HEAT_PUMP
            )
        else:
            self._attr_current_operation = STATE_OFF

        _LOGGER.debug(
            "[%s:%s] update status: c:%s, t:%s, op_mode:%s, op_list:%s, is_on:%s",
            self.coordinator.device_name,
            self.property_id,
            self.current_temperature,
            self.target_temperature,
            self.current_operation,
            self.operation_list,
            self.data.is_on,
        )

    @override
    async def async_set_temperature(self, **kwargs: Any) -> None:
        """Set new target temperatures."""
        _LOGGER.debug(
            "[%s:%s] async_set_temperature: %s",
            self.coordinator.device_name,
            self.property_id,
            kwargs,
        )
        if (operation_mode := kwargs.get(ATTR_OPERATION_MODE)) is not None:
            await self.async_set_operation_mode(str(operation_mode))
            if operation_mode == STATE_OFF:
                return

        if (
            temperature := kwargs.get(ATTR_TEMPERATURE)
        ) is not None and temperature != self.target_temperature:
            await self.async_call_api(
                self.coordinator.api.async_set_target_temperature(
                    self.property_id, temperature
                )
            )

    @override
    async def async_set_operation_mode(self, operation_mode: str) -> None:
        """Set new operation mode."""
        mode = HA_STATE_TO_DEVICE_OP_MODE.get(operation_mode, operation_mode)
        _LOGGER.debug(
            "[%s:%s] async_set_operation_mode: %s",
            self.coordinator.device_name,
            self.property_id,
            mode,
        )
        await self.async_call_api(
            self.coordinator.api.async_set_job_mode(self.property_id, mode)
        )


class ThinQWaterBoilerEntity(ThinQWaterHeaterEntity):
    """Represent a ThinQ water boiler entity."""

    def __init__(
        self,
        coordinator: DeviceDataUpdateCoordinator,
        entity_description: WaterHeaterEntityDescription,
        property_id: str,
    ) -> None:
        """Initialize a water_heater entity."""
        super().__init__(coordinator, entity_description, property_id)
        self._attr_supported_features |= WaterHeaterEntityFeature.ON_OFF
        # For SYSTEM_BOILER, we only support heat pump mode and off mode.
        self._attr_operation_list = [STATE_HEAT_PUMP, STATE_OFF]

    @override
    async def async_turn_on(self, **kwargs: Any) -> None:
        """Turn the entity on."""
        _LOGGER.debug(
            "[%s:%s] async_turn_on", self.coordinator.device_name, self.property_id
        )
        await self.async_call_api(self.coordinator.api.async_turn_on(self.property_id))

    @override
    async def async_turn_off(self, **kwargs: Any) -> None:
        """Turn the entity off."""
        _LOGGER.debug(
            "[%s:%s] async_turn_off", self.coordinator.device_name, self.property_id
        )
        await self.async_call_api(self.coordinator.api.async_turn_off(self.property_id))

    @override
    async def async_set_operation_mode(self, operation_mode: str) -> None:
        """Set new operation mode."""
        _LOGGER.debug(
            "[%s:%s] async_set_operation_mode: %s",
            self.coordinator.device_name,
            self.property_id,
            operation_mode,
        )
        if operation_mode == STATE_OFF:
            await self.async_turn_off()
        else:
            await self.async_turn_on()
