"""Support for number entities."""

from __future__ import annotations

import logging

from thinqconnect import DeviceType
from thinqconnect.devices.const import Property as ThinQProperty
from thinqconnect.integration import ActiveMode, TimerProperty

from homeassistant.components.number import (
    NumberDeviceClass,
    NumberEntity,
    NumberEntityDescription,
    NumberMode,
)
from homeassistant.const import PERCENTAGE, UnitOfTemperature, UnitOfTime
from homeassistant.core import HomeAssistant
from homeassistant.helpers.entity_platform import AddConfigEntryEntitiesCallback

from . import ThinqConfigEntry
from .entity import ThinQEntity

NUMBER_DESC: dict[ThinQProperty, NumberEntityDescription] = {
    ThinQProperty.FAN_SPEED: NumberEntityDescription(
        key=ThinQProperty.FAN_SPEED,
        translation_key=ThinQProperty.FAN_SPEED,
    ),
    ThinQProperty.LAMP_BRIGHTNESS: NumberEntityDescription(
        key=ThinQProperty.LAMP_BRIGHTNESS,
        translation_key=ThinQProperty.LAMP_BRIGHTNESS,
    ),
    ThinQProperty.LIGHT_STATUS: NumberEntityDescription(
        key=ThinQProperty.LIGHT_STATUS,
        native_unit_of_measurement=PERCENTAGE,
        translation_key=ThinQProperty.LIGHT_STATUS,
    ),
    ThinQProperty.TARGET_HUMIDITY: NumberEntityDescription(
        key=ThinQProperty.TARGET_HUMIDITY,
        device_class=NumberDeviceClass.HUMIDITY,
        native_unit_of_measurement=PERCENTAGE,
        translation_key=ThinQProperty.TARGET_HUMIDITY,
    ),
    ThinQProperty.TARGET_TEMPERATURE: NumberEntityDescription(
        key=ThinQProperty.TARGET_TEMPERATURE,
        native_unit_of_measurement=UnitOfTemperature.CELSIUS,
        translation_key=ThinQProperty.TARGET_TEMPERATURE,
    ),
    ThinQProperty.WIND_TEMPERATURE: NumberEntityDescription(
        key=ThinQProperty.WIND_TEMPERATURE,
        native_unit_of_measurement=UnitOfTemperature.CELSIUS,
        translation_key=ThinQProperty.WIND_TEMPERATURE,
    ),
}
TIMER_NUMBER_DESC: dict[ThinQProperty, NumberEntityDescription] = {
    ThinQProperty.RELATIVE_HOUR_TO_START: NumberEntityDescription(
        key=ThinQProperty.RELATIVE_HOUR_TO_START,
        native_unit_of_measurement=UnitOfTime.HOURS,
        translation_key=ThinQProperty.RELATIVE_HOUR_TO_START,
    ),
    TimerProperty.RELATIVE_HOUR_TO_START_WM: NumberEntityDescription(
        key=ThinQProperty.RELATIVE_HOUR_TO_START,
        native_min_value=0,
        native_unit_of_measurement=UnitOfTime.HOURS,
        translation_key=TimerProperty.RELATIVE_HOUR_TO_START_WM,
    ),
    ThinQProperty.RELATIVE_HOUR_TO_STOP: NumberEntityDescription(
        key=ThinQProperty.RELATIVE_HOUR_TO_STOP,
        native_unit_of_measurement=UnitOfTime.HOURS,
        translation_key=ThinQProperty.RELATIVE_HOUR_TO_STOP,
    ),
    TimerProperty.RELATIVE_HOUR_TO_STOP_WM: NumberEntityDescription(
        key=ThinQProperty.RELATIVE_HOUR_TO_STOP,
        native_min_value=0,
        native_unit_of_measurement=UnitOfTime.HOURS,
        translation_key=TimerProperty.RELATIVE_HOUR_TO_STOP_WM,
    ),
    ThinQProperty.SLEEP_TIMER_RELATIVE_HOUR_TO_STOP: NumberEntityDescription(
        key=ThinQProperty.SLEEP_TIMER_RELATIVE_HOUR_TO_STOP,
        native_unit_of_measurement=UnitOfTime.HOURS,
        translation_key=ThinQProperty.SLEEP_TIMER_RELATIVE_HOUR_TO_STOP,
    ),
}
WASHER_NUMBERS: tuple[NumberEntityDescription, ...] = (
    TIMER_NUMBER_DESC[TimerProperty.RELATIVE_HOUR_TO_START_WM],
    TIMER_NUMBER_DESC[TimerProperty.RELATIVE_HOUR_TO_STOP_WM],
)

DEVICE_TYPE_NUMBER_MAP: dict[DeviceType, tuple[NumberEntityDescription, ...]] = {
    DeviceType.AIR_CONDITIONER: (
        TIMER_NUMBER_DESC[ThinQProperty.RELATIVE_HOUR_TO_START],
        TIMER_NUMBER_DESC[ThinQProperty.RELATIVE_HOUR_TO_STOP],
        TIMER_NUMBER_DESC[ThinQProperty.SLEEP_TIMER_RELATIVE_HOUR_TO_STOP],
    ),
    DeviceType.AIR_PURIFIER_FAN: (
        NUMBER_DESC[ThinQProperty.WIND_TEMPERATURE],
        TIMER_NUMBER_DESC[ThinQProperty.SLEEP_TIMER_RELATIVE_HOUR_TO_STOP],
    ),
    DeviceType.DRYER: WASHER_NUMBERS,
    DeviceType.HOOD: (
        NUMBER_DESC[ThinQProperty.LAMP_BRIGHTNESS],
        NUMBER_DESC[ThinQProperty.FAN_SPEED],
    ),
    DeviceType.HUMIDIFIER: (
        NUMBER_DESC[ThinQProperty.TARGET_HUMIDITY],
        TIMER_NUMBER_DESC[ThinQProperty.SLEEP_TIMER_RELATIVE_HOUR_TO_STOP],
    ),
    DeviceType.MICROWAVE_OVEN: (
        NUMBER_DESC[ThinQProperty.LAMP_BRIGHTNESS],
        NUMBER_DESC[ThinQProperty.FAN_SPEED],
    ),
    DeviceType.OVEN: (NUMBER_DESC[ThinQProperty.TARGET_TEMPERATURE],),
    DeviceType.REFRIGERATOR: (NUMBER_DESC[ThinQProperty.TARGET_TEMPERATURE],),
    DeviceType.STYLER: (TIMER_NUMBER_DESC[TimerProperty.RELATIVE_HOUR_TO_STOP_WM],),
    DeviceType.WASHCOMBO_MAIN: WASHER_NUMBERS,
    DeviceType.WASHCOMBO_MINI: WASHER_NUMBERS,
    DeviceType.WASHER: WASHER_NUMBERS,
    DeviceType.WASHTOWER_DRYER: WASHER_NUMBERS,
    DeviceType.WASHTOWER: WASHER_NUMBERS,
    DeviceType.WASHTOWER_WASHER: WASHER_NUMBERS,
    DeviceType.WATER_HEATER: (NUMBER_DESC[ThinQProperty.TARGET_TEMPERATURE],),
    DeviceType.WINE_CELLAR: (
        NUMBER_DESC[ThinQProperty.LIGHT_STATUS],
        NUMBER_DESC[ThinQProperty.TARGET_TEMPERATURE],
    ),
    DeviceType.VENTILATOR: (
        TIMER_NUMBER_DESC[ThinQProperty.SLEEP_TIMER_RELATIVE_HOUR_TO_STOP],
    ),
}

_LOGGER = logging.getLogger(__name__)


async def async_setup_entry(
    hass: HomeAssistant,
    entry: ThinqConfigEntry,
    async_add_entities: AddConfigEntryEntitiesCallback,
) -> None:
    """Set up an entry for number platform."""
    entities: list[ThinQNumberEntity] = []
    for coordinator in entry.runtime_data.coordinators.values():
        if (
            descriptions := DEVICE_TYPE_NUMBER_MAP.get(
                coordinator.api.device.device_type
            )
        ) is not None:
            for description in descriptions:
                entities.extend(
                    ThinQNumberEntity(coordinator, description, property_id)
                    for property_id in coordinator.api.get_active_idx(
                        description.key, ActiveMode.READ_WRITE
                    )
                )

    if entities:
        async_add_entities(entities)


class ThinQNumberEntity(ThinQEntity, NumberEntity):
    """Represent a thinq number platform."""

    _attr_mode = NumberMode.BOX

    def _update_status(self) -> None:
        """Update status itself."""
        super()._update_status()

        self._attr_native_value = self.data.value

        # Update unit.
        if (
            unit_of_measurement := self._get_unit_of_measurement(self.data.unit)
        ) is not None:
            self._attr_native_unit_of_measurement = unit_of_measurement

        # Update range.
        if (
            self.entity_description.native_min_value is None
            and (min_value := self.data.min) is not None
        ):
            self._attr_native_min_value = min_value

        if (
            self.entity_description.native_max_value is None
            and (max_value := self.data.max) is not None
        ):
            self._attr_native_max_value = max_value

        if (
            self.entity_description.native_step is None
            and (step := self.data.step) is not None
        ):
            self._attr_native_step = step

        _LOGGER.debug(
            "[%s:%s] update status: %s -> %s, unit:%s, min:%s, max:%s, step:%s",
            self.coordinator.device_name,
            self.property_id,
            self.data.value,
            self.native_value,
            self.native_unit_of_measurement,
            self.native_min_value,
            self.native_max_value,
            self.native_step,
        )

    async def async_set_native_value(self, value: float) -> None:
        """Change to new number value."""
        if self.step.is_integer():
            value = int(value)
        _LOGGER.debug(
            "[%s:%s] async_set_native_value: %s",
            self.coordinator.device_name,
            self.property_id,
            value,
        )

        await self.async_call_api(self.coordinator.api.post(self.property_id, value))
