"""Support for humidifiers."""

from __future__ import annotations

from enum import StrEnum
from typing import Any, cast

from aiocomelit import ComelitSerialBridgeObject
from aiocomelit.const import CLIMATE

from homeassistant.components.humidifier import (
    DOMAIN as HUMIDIFIER_DOMAIN,
    MODE_AUTO,
    MODE_NORMAL,
    HumidifierAction,
    HumidifierDeviceClass,
    HumidifierEntity,
    HumidifierEntityFeature,
)
from homeassistant.core import HomeAssistant, callback
from homeassistant.exceptions import ServiceValidationError
from homeassistant.helpers.entity_platform import AddConfigEntryEntitiesCallback

from .const import DOMAIN
from .coordinator import ComelitConfigEntry, ComelitSerialBridge
from .entity import ComelitBridgeBaseEntity
from .utils import bridge_api_call, cleanup_stale_entity, load_api_data

# Coordinator is used to centralize the data updates
PARALLEL_UPDATES = 0


class HumidifierComelitMode(StrEnum):
    """Serial Bridge humidifier modes."""

    AUTO = "A"
    OFF = "O"
    LOWER = "L"
    UPPER = "U"


class HumidifierComelitCommand(StrEnum):
    """Serial Bridge humidifier commands."""

    OFF = "off"
    ON = "on"
    MANUAL = "man"
    SET = "set"
    AUTO = "auto"
    LOWER = "lower"
    UPPER = "upper"


MODE_TO_ACTION: dict[str, HumidifierComelitCommand] = {
    MODE_AUTO: HumidifierComelitCommand.AUTO,
    MODE_NORMAL: HumidifierComelitCommand.MANUAL,
}


async def async_setup_entry(
    hass: HomeAssistant,
    config_entry: ComelitConfigEntry,
    async_add_entities: AddConfigEntryEntitiesCallback,
) -> None:
    """Set up Comelit humidifiers."""

    coordinator = cast(ComelitSerialBridge, config_entry.runtime_data)

    entities: list[ComelitHumidifierEntity] = []
    for device in coordinator.data[CLIMATE].values():
        values = load_api_data(device, HUMIDIFIER_DOMAIN)
        if values[0] == 0 and values[4] == 0:
            # No humidity data, device is only a climate

            for device_class in (
                HumidifierDeviceClass.HUMIDIFIER,
                HumidifierDeviceClass.DEHUMIDIFIER,
            ):
                await cleanup_stale_entity(
                    hass,
                    config_entry,
                    f"{config_entry.entry_id}-{device.index}-{device_class}",
                    device,
                )

            continue

        entities.append(
            ComelitHumidifierEntity(
                coordinator,
                device,
                config_entry.entry_id,
                active_mode=HumidifierComelitMode.LOWER,
                active_action=HumidifierAction.DRYING,
                set_command=HumidifierComelitCommand.LOWER,
                device_class=HumidifierDeviceClass.DEHUMIDIFIER,
            )
        )
        entities.append(
            ComelitHumidifierEntity(
                coordinator,
                device,
                config_entry.entry_id,
                active_mode=HumidifierComelitMode.UPPER,
                active_action=HumidifierAction.HUMIDIFYING,
                set_command=HumidifierComelitCommand.UPPER,
                device_class=HumidifierDeviceClass.HUMIDIFIER,
            ),
        )

    async_add_entities(entities)


class ComelitHumidifierEntity(ComelitBridgeBaseEntity, HumidifierEntity):
    """Humidifier device."""

    _attr_supported_features = HumidifierEntityFeature.MODES
    _attr_available_modes = [MODE_NORMAL, MODE_AUTO]
    _attr_min_humidity = 10
    _attr_max_humidity = 90

    def __init__(
        self,
        coordinator: ComelitSerialBridge,
        device: ComelitSerialBridgeObject,
        config_entry_entry_id: str,
        active_mode: HumidifierComelitMode,
        active_action: HumidifierAction,
        set_command: HumidifierComelitCommand,
        device_class: HumidifierDeviceClass,
    ) -> None:
        """Init light entity."""
        super().__init__(coordinator, device, config_entry_entry_id)
        self._attr_unique_id = f"{config_entry_entry_id}-{device.index}-{device_class}"
        self._attr_device_class = device_class
        self._attr_translation_key = device_class.value
        self._active_mode = active_mode
        self._active_action = active_action
        self._set_command = set_command
        self._update_attributes()

    def _update_attributes(self) -> None:
        """Update class attributes."""
        device = self.coordinator.data[CLIMATE][self._device.index]
        values = load_api_data(device, HUMIDIFIER_DOMAIN)

        _active = values[1]
        _mode = values[2]  # Values from API: "O", "L", "U"
        _automatic = values[3] == HumidifierComelitMode.AUTO

        self._attr_action = HumidifierAction.IDLE
        if _mode == HumidifierComelitMode.OFF:
            self._attr_action = HumidifierAction.OFF
        if _active and _mode == self._active_mode:
            self._attr_action = self._active_action

        self._attr_current_humidity = values[0] / 10
        self._attr_is_on = _mode == self._active_mode
        self._attr_mode = MODE_AUTO if _automatic else MODE_NORMAL
        self._attr_target_humidity = values[4] / 10

    @callback
    def _handle_coordinator_update(self) -> None:
        """Handle updated data from the coordinator."""
        self._update_attributes()
        super()._handle_coordinator_update()

    @bridge_api_call
    async def async_set_humidity(self, humidity: int) -> None:
        """Set new target humidity."""
        if not self._attr_is_on:
            raise ServiceValidationError(
                translation_domain=DOMAIN,
                translation_key="humidity_while_off",
            )

        await self.coordinator.api.set_humidity_status(
            self._device.index, HumidifierComelitCommand.MANUAL
        )
        await self.coordinator.api.set_humidity_status(
            self._device.index, HumidifierComelitCommand.SET, humidity
        )
        self._attr_target_humidity = humidity
        self.async_write_ha_state()

    @bridge_api_call
    async def async_set_mode(self, mode: str) -> None:
        """Set humidifier mode."""
        await self.coordinator.api.set_humidity_status(
            self._device.index, MODE_TO_ACTION[mode]
        )
        self._attr_mode = mode
        self.async_write_ha_state()

    @bridge_api_call
    async def async_turn_on(self, **kwargs: Any) -> None:
        """Turn on."""
        await self.coordinator.api.set_humidity_status(
            self._device.index, self._set_command
        )
        self._attr_is_on = True
        self.async_write_ha_state()

    @bridge_api_call
    async def async_turn_off(self, **kwargs: Any) -> None:
        """Turn off."""
        await self.coordinator.api.set_humidity_status(
            self._device.index, HumidifierComelitCommand.OFF
        )
        self._attr_is_on = False
        self.async_write_ha_state()
