"""Support for ZHA controls using the select platform."""

from __future__ import annotations

from dataclasses import dataclass
from enum import Enum
import functools
import logging
from typing import TYPE_CHECKING, Any

from zhaquirks.danfoss import thermostat as danfoss_thermostat
from zhaquirks.quirk_ids import (
    DANFOSS_ALLY_THERMOSTAT,
    TUYA_PLUG_MANUFACTURER,
    TUYA_PLUG_ONOFF,
)
from zhaquirks.xiaomi.aqara.magnet_ac01 import OppleCluster as MagnetAC01OppleCluster
from zhaquirks.xiaomi.aqara.switch_acn047 import OppleCluster as T2RelayOppleCluster
from zigpy import types
from zigpy.quirks.v2 import ZCLEnumMetadata
from zigpy.zcl.clusters.general import OnOff
from zigpy.zcl.clusters.hvac import Thermostat, UserInterface
from zigpy.zcl.clusters.measurement import OccupancySensing
from zigpy.zcl.clusters.security import IasWd

from zha.application import Platform
from zha.application.const import Strobe
from zha.application.platforms import (
    BaseEntityInfo,
    ClusterHandlerMatch,
    EntityCategory,
    PlatformEntity,
    register_entity,
)
from zha.zigbee.cluster_handlers import ClusterAttributeUpdatedEvent
from zha.zigbee.cluster_handlers.const import (
    AQARA_OPPLE_CLUSTER,
    CLUSTER_HANDLER_ATTRIBUTE_UPDATED,
    CLUSTER_HANDLER_HUE_OCCUPANCY,
    CLUSTER_HANDLER_IAS_WD,
    CLUSTER_HANDLER_INOVELLI,
    CLUSTER_HANDLER_OCCUPANCY,
    CLUSTER_HANDLER_ON_OFF,
    CLUSTER_HANDLER_THERMOSTAT,
    INOVELLI_CLUSTER,
    SINOPE_MANUFACTURER_CLUSTER,
    TUYA_MANUFACTURER_CLUSTER,
)

if TYPE_CHECKING:
    from zha.zigbee.cluster_handlers import ClusterHandler
    from zha.zigbee.device import Device
    from zha.zigbee.endpoint import Endpoint

_LOGGER = logging.getLogger(__name__)


@dataclass(frozen=True, kw_only=True)
class EnumSelectInfo(BaseEntityInfo):
    """Enum select entity info."""

    enum: str
    options: list[str]


class EnumSelectEntity(PlatformEntity):
    """Representation of a ZHA select entity."""

    PLATFORM = Platform.SELECT
    _attr_entity_category = EntityCategory.CONFIG
    _attribute_name: str
    _enum: type[Enum]

    def __init__(
        self,
        cluster_handlers: list[ClusterHandler],
        endpoint: Endpoint,
        device: Device,
        **kwargs: Any,
    ) -> None:
        """Init this select entity."""
        self._cluster_handler: ClusterHandler = cluster_handlers[0]
        self._attribute_name = self._enum.__name__
        self._attr_options = [entry.name.replace("_", " ") for entry in self._enum]
        super().__init__(cluster_handlers, endpoint, device, **kwargs)

    @functools.cached_property
    def info_object(self) -> EnumSelectInfo:
        """Return a representation of the select."""
        return EnumSelectInfo(
            **super().info_object.__dict__,
            enum=self._enum.__name__,
            options=self._attr_options,
        )

    @property
    def state(self) -> dict:
        """Return the state of the select."""
        response = super().state
        response["state"] = self.current_option
        return response

    @property
    def current_option(self) -> str | None:
        """Return the selected entity option to represent the entity state."""
        option = self._cluster_handler.data_cache.get(self._attribute_name)
        if option is None:
            return None
        return option.name.replace("_", " ")

    async def async_select_option(self, option: str) -> None:
        """Change the selected option."""
        self._cluster_handler.data_cache[self._attribute_name] = self._enum[
            option.replace(" ", "_")
        ]
        self.maybe_emit_state_changed_event()

    def restore_external_state_attributes(
        self,
        *,
        state: str,
    ) -> None:
        """Restore extra state attributes that are stored outside of the ZCL cache."""
        value = state.replace(" ", "_")
        self._cluster_handler.data_cache[self._attribute_name] = self._enum[value]


class NonZCLSelectEntity(EnumSelectEntity):
    """Representation of a ZHA select entity with no ZCL interaction."""

    @property
    def available(self) -> bool:
        """Return entity availability."""
        return True


@register_entity(IasWd.cluster_id)
class DefaultToneSelectEntity(NonZCLSelectEntity):
    """Representation of a ZHA default siren tone select entity."""

    _unique_id_suffix = "WarningMode"
    _enum = IasWd.Warning.WarningMode
    _attr_translation_key: str = "default_siren_tone"

    _cluster_handler_match = ClusterHandlerMatch(
        cluster_handlers=frozenset({CLUSTER_HANDLER_IAS_WD})
    )


@register_entity(IasWd.cluster_id)
class DefaultSirenLevelSelectEntity(NonZCLSelectEntity):
    """Representation of a ZHA default siren level select entity."""

    _unique_id_suffix = "SirenLevel"
    _enum = IasWd.Warning.SirenLevel
    _attr_translation_key: str = "default_siren_level"

    _cluster_handler_match = ClusterHandlerMatch(
        cluster_handlers=frozenset({CLUSTER_HANDLER_IAS_WD})
    )


@register_entity(IasWd.cluster_id)
class DefaultStrobeLevelSelectEntity(NonZCLSelectEntity):
    """Representation of a ZHA default siren strobe level select entity."""

    _unique_id_suffix = "StrobeLevel"
    _enum = IasWd.StrobeLevel
    _attr_translation_key: str = "default_strobe_level"

    _cluster_handler_match = ClusterHandlerMatch(
        cluster_handlers=frozenset({CLUSTER_HANDLER_IAS_WD})
    )


@register_entity(IasWd.cluster_id)
class DefaultStrobeSelectEntity(NonZCLSelectEntity):
    """Representation of a ZHA default siren strobe select entity."""

    _unique_id_suffix = "Strobe"
    _enum = Strobe
    _attr_translation_key: str = "default_strobe"

    _cluster_handler_match = ClusterHandlerMatch(
        cluster_handlers=frozenset({CLUSTER_HANDLER_IAS_WD})
    )


class ZCLEnumSelectEntity(PlatformEntity):
    """Representation of a ZHA ZCL enum select entity."""

    PLATFORM = Platform.SELECT
    _attribute_name: str
    _attr_entity_category = EntityCategory.CONFIG
    _enum: type[Enum]

    def __init__(
        self,
        cluster_handlers: list[ClusterHandler],
        endpoint: Endpoint,
        device: Device,
        **kwargs: Any,
    ) -> None:
        """Init this select entity."""
        super().__init__(cluster_handlers, endpoint, device, **kwargs)
        self._cluster_handler: ClusterHandler = cluster_handlers[0]
        self._attr_options = [entry.name.replace("_", " ") for entry in self._enum]

    def on_add(self) -> None:
        """Run when entity is added."""
        super().on_add()
        self._on_remove_callbacks.append(
            self._cluster_handler.on_event(
                CLUSTER_HANDLER_ATTRIBUTE_UPDATED,
                self.handle_cluster_handler_attribute_updated,
            )
        )

    def _is_supported(self) -> bool:
        if (
            self._attribute_name not in self._cluster_handler.cluster.attributes_by_name
            or self._cluster_handler.cluster.is_attribute_unsupported(
                self._attribute_name
            )
            or self._cluster_handler.cluster.get(self._attribute_name) is None
        ):
            _LOGGER.debug(
                "%s is not supported - skipping %s entity creation",
                self._attribute_name,
                self.__class__.__name__,
            )
            return False

        return super()._is_supported()

    def _init_from_quirks_metadata(self, entity_metadata: ZCLEnumMetadata) -> None:
        """Init this entity from the quirks metadata."""
        super()._init_from_quirks_metadata(entity_metadata)
        self._attribute_name = entity_metadata.attribute_name
        self._enum = entity_metadata.enum

    @functools.cached_property
    def info_object(self) -> EnumSelectInfo:
        """Return a representation of the select."""
        return EnumSelectInfo(
            **super().info_object.__dict__,
            enum=self._enum.__name__,
            options=self._attr_options,
        )

    @property
    def state(self) -> dict[str, Any]:
        """Return the state of the select."""
        response = super().state
        response["state"] = self.current_option
        return response

    @property
    def current_option(self) -> str | None:
        """Return the selected entity option to represent the entity state."""
        option = self._cluster_handler.cluster.get(self._attribute_name)
        if option is None:
            return None
        option = self._enum(option)
        return option.name.replace("_", " ")

    async def async_select_option(self, option: str) -> None:
        """Change the selected option."""
        await self._cluster_handler.write_attributes_safe(
            {self._attribute_name: self._enum[option.replace(" ", "_")]}
        )
        self.maybe_emit_state_changed_event()

    def handle_cluster_handler_attribute_updated(
        self,
        event: ClusterAttributeUpdatedEvent,  # pylint: disable=unused-argument
    ) -> None:
        """Handle value update from cluster handler."""
        if event.attribute_name == self._attribute_name:
            self.maybe_emit_state_changed_event()

    def restore_external_state_attributes(
        self,
        *,
        state: str,
    ) -> None:
        """Restore extra state attributes."""
        # Select entities backed by the ZCL cache don't need to restore their state!


@register_entity(OnOff.cluster_id)
class StartupOnOffSelectEntity(ZCLEnumSelectEntity):
    """Representation of a ZHA startup onoff select entity."""

    _unique_id_suffix = "StartUpOnOff"
    _attribute_name = "start_up_on_off"
    _enum = OnOff.StartUpOnOff
    _attr_translation_key: str = "start_up_on_off"

    _cluster_handler_match = ClusterHandlerMatch(
        cluster_handlers=frozenset({CLUSTER_HANDLER_ON_OFF})
    )


class TuyaPowerOnState(types.enum8):
    """Tuya power on state enum."""

    Off = 0x00
    On = 0x01
    LastState = 0x02


@register_entity(OnOff.cluster_id)
class TuyaPowerOnStateSelectEntity(ZCLEnumSelectEntity):
    """Representation of a ZHA power on state select entity."""

    _unique_id_suffix = "power_on_state"
    _attribute_name = "power_on_state"
    _enum = TuyaPowerOnState
    _attr_translation_key: str = "power_on_state"

    _cluster_handler_match = ClusterHandlerMatch(
        cluster_handlers=frozenset({CLUSTER_HANDLER_ON_OFF}),
        exposed_features=frozenset({TUYA_PLUG_ONOFF}),
    )


@register_entity(TUYA_MANUFACTURER_CLUSTER)
class TuyaManufacturerPowerOnStateSelectEntity(ZCLEnumSelectEntity):
    """Representation of a ZHA power on state select entity."""

    _unique_id_suffix = "power_on_state"
    _attribute_name = "power_on_state"
    _enum = TuyaPowerOnState
    _attr_translation_key: str = "power_on_state"

    _cluster_handler_match = ClusterHandlerMatch(
        cluster_handlers=frozenset({"tuya_manufacturer"}),
        exposed_features=frozenset({TUYA_PLUG_MANUFACTURER}),
    )


class TuyaBacklightMode(types.enum8):
    """Tuya switch backlight mode enum."""

    Off = 0x00
    LightWhenOn = 0x01
    LightWhenOff = 0x02


@register_entity(OnOff.cluster_id)
class TuyaBacklightModeSelectEntity(ZCLEnumSelectEntity):
    """Representation of a ZHA backlight mode select entity."""

    _unique_id_suffix = "backlight_mode"
    _attribute_name = "backlight_mode"
    _enum = TuyaBacklightMode
    _attr_translation_key: str = "backlight_mode"

    _cluster_handler_match = ClusterHandlerMatch(
        cluster_handlers=frozenset({CLUSTER_HANDLER_ON_OFF}),
        exposed_features=frozenset({TUYA_PLUG_ONOFF}),
    )


class MoesBacklightMode(types.enum8):
    """MOES switch backlight mode enum."""

    Off = 0x00
    LightWhenOn = 0x01
    LightWhenOff = 0x02
    Freeze = 0x03


@register_entity(TUYA_MANUFACTURER_CLUSTER)
class MoesBacklightModeSelectEntity(ZCLEnumSelectEntity):
    """Moes devices have a different backlight mode select options."""

    _unique_id_suffix = "backlight_mode"
    _attribute_name = "backlight_mode"
    _enum = MoesBacklightMode
    _attr_translation_key: str = "backlight_mode"

    _cluster_handler_match = ClusterHandlerMatch(
        cluster_handlers=frozenset({"tuya_manufacturer"}),
        exposed_features=frozenset({TUYA_PLUG_MANUFACTURER}),
    )


class AqaraMotionSensitivities(types.enum8):
    """Aqara motion sensitivities."""

    Low = 0x01
    Medium = 0x02
    High = 0x03


@register_entity(AQARA_OPPLE_CLUSTER)
class AqaraMotionSensitivity(ZCLEnumSelectEntity):
    """Representation of a ZHA motion sensitivity configuration entity."""

    _unique_id_suffix = "motion_sensitivity"
    _attribute_name = "motion_sensitivity"
    _enum = AqaraMotionSensitivities
    _attr_translation_key: str = "motion_sensitivity"

    _cluster_handler_match = ClusterHandlerMatch(
        cluster_handlers=frozenset({"opple_cluster"}),
        models=frozenset({"lumi.motion.ac01", "lumi.motion.ac02", "lumi.motion.agl04"}),
    )


class HueV1MotionSensitivities(types.enum8):
    """Hue v1 motion sensitivities."""

    Low = 0x00
    Medium = 0x01
    High = 0x02


@register_entity(OccupancySensing.cluster_id)
class HueV1MotionSensitivity(ZCLEnumSelectEntity):
    """Representation of a ZHA motion sensitivity configuration entity."""

    _unique_id_suffix = "motion_sensitivity"
    _attribute_name = "sensitivity"
    _enum = HueV1MotionSensitivities
    _attr_translation_key: str = "motion_sensitivity"

    _cluster_handler_match = ClusterHandlerMatch(
        cluster_handlers=frozenset({CLUSTER_HANDLER_HUE_OCCUPANCY}),
        manufacturers=frozenset({"Philips", "Signify Netherlands B.V."}),
        models=frozenset({"SML001"}),
    )


class HueV2MotionSensitivities(types.enum8):
    """Hue v2 motion sensitivities."""

    Lowest = 0x00
    Low = 0x01
    Medium = 0x02
    High = 0x03
    Highest = 0x04


@register_entity(OccupancySensing.cluster_id)
class HueV2MotionSensitivity(ZCLEnumSelectEntity):
    """Representation of a ZHA motion sensitivity configuration entity."""

    _unique_id_suffix = "motion_sensitivity"
    _attribute_name = "sensitivity"
    _enum = HueV2MotionSensitivities
    _attr_translation_key: str = "motion_sensitivity"

    _cluster_handler_match = ClusterHandlerMatch(
        cluster_handlers=frozenset({CLUSTER_HANDLER_HUE_OCCUPANCY}),
        manufacturers=frozenset({"Philips", "Signify Netherlands B.V."}),
        models=frozenset({"SML002", "SML003", "SML004"}),
    )


class AqaraMonitoringModess(types.enum8):
    """Aqara monitoring modes."""

    Undirected = 0x00
    Left_Right = 0x01


@register_entity(AQARA_OPPLE_CLUSTER)
class AqaraMonitoringMode(ZCLEnumSelectEntity):
    """Representation of a ZHA monitoring mode configuration entity."""

    _unique_id_suffix = "monitoring_mode"
    _attribute_name = "monitoring_mode"
    _enum = AqaraMonitoringModess
    _attr_translation_key: str = "monitoring_mode"

    _cluster_handler_match = ClusterHandlerMatch(
        cluster_handlers=frozenset({"opple_cluster"}),
        models=frozenset({"lumi.motion.ac01"}),
    )


class AqaraApproachDistances(types.enum8):
    """Aqara approach distances."""

    Far = 0x00
    Medium = 0x01
    Near = 0x02


@register_entity(AQARA_OPPLE_CLUSTER)
class AqaraApproachDistance(ZCLEnumSelectEntity):
    """Representation of a ZHA approach distance configuration entity."""

    _unique_id_suffix = "approach_distance"
    _attribute_name = "approach_distance"
    _enum = AqaraApproachDistances
    _attr_translation_key: str = "approach_distance"

    _cluster_handler_match = ClusterHandlerMatch(
        cluster_handlers=frozenset({"opple_cluster"}),
        models=frozenset({"lumi.motion.ac01"}),
    )


@register_entity(MagnetAC01OppleCluster.cluster_id)
class AqaraMagnetAC01DetectionDistance(ZCLEnumSelectEntity):
    """Representation of a ZHA detection distance configuration entity."""

    _unique_id_suffix = "detection_distance"
    _attribute_name = "detection_distance"
    _enum = MagnetAC01OppleCluster.DetectionDistance
    _attr_translation_key: str = "detection_distance"

    _cluster_handler_match = ClusterHandlerMatch(
        cluster_handlers=frozenset({"opple_cluster"}),
        models=frozenset({"lumi.magnet.ac01"}),
    )


@register_entity(T2RelayOppleCluster.cluster_id)
class AqaraT2RelaySwitchMode(ZCLEnumSelectEntity):
    """Representation of a ZHA switch mode configuration entity."""

    _unique_id_suffix = "switch_mode"
    _attribute_name = "switch_mode"
    _enum = T2RelayOppleCluster.SwitchMode
    _attr_translation_key: str = "switch_mode"

    _cluster_handler_match = ClusterHandlerMatch(
        cluster_handlers=frozenset({"opple_cluster"}),
        models=frozenset({"lumi.switch.acn047"}),
    )


@register_entity(T2RelayOppleCluster.cluster_id)
class AqaraT2RelaySwitchType(ZCLEnumSelectEntity):
    """Representation of a ZHA switch type configuration entity."""

    _unique_id_suffix = "switch_type"
    _attribute_name = "switch_type"
    _enum = T2RelayOppleCluster.SwitchType
    _attr_translation_key: str = "switch_type"

    _cluster_handler_match = ClusterHandlerMatch(
        cluster_handlers=frozenset({"opple_cluster"}),
        models=frozenset({"lumi.switch.acn047"}),
    )


@register_entity(T2RelayOppleCluster.cluster_id)
class AqaraT2RelayStartupOnOff(ZCLEnumSelectEntity):
    """Representation of a ZHA startup on off configuration entity."""

    _unique_id_suffix = "startup_on_off"
    _attribute_name = "startup_on_off"
    _enum = T2RelayOppleCluster.StartupOnOff
    _attr_translation_key: str = "start_up_on_off"

    _cluster_handler_match = ClusterHandlerMatch(
        cluster_handlers=frozenset({"opple_cluster"}),
        models=frozenset({"lumi.switch.acn047"}),
    )


@register_entity(T2RelayOppleCluster.cluster_id)
class AqaraT2RelayDecoupledMode(ZCLEnumSelectEntity):
    """Representation of a ZHA switch decoupled mode configuration entity."""

    _unique_id_suffix = "decoupled_mode"
    _attribute_name = "decoupled_mode"
    _enum = T2RelayOppleCluster.DecoupledMode
    _attr_translation_key: str = "decoupled_mode"

    _cluster_handler_match = ClusterHandlerMatch(
        cluster_handlers=frozenset({"opple_cluster"}),
        models=frozenset({"lumi.switch.acn047"}),
    )


class InovelliOutputMode(types.enum1):
    """Inovelli output mode."""

    Dimmer = 0x00
    OnOff = 0x01


@register_entity(INOVELLI_CLUSTER)
class InovelliOutputModeEntity(ZCLEnumSelectEntity):
    """Inovelli output mode control."""

    _unique_id_suffix = "output_mode"
    _attribute_name = "output_mode"
    _enum = InovelliOutputMode
    _attr_translation_key: str = "output_mode"

    _cluster_handler_match = ClusterHandlerMatch(
        cluster_handlers=frozenset({CLUSTER_HANDLER_INOVELLI})
    )


class InovelliSwitchType(types.enum8):
    """Inovelli switch mode."""

    Single_Pole = 0x00
    Three_Way_Dumb = 0x01
    Three_Way_AUX = 0x02
    Single_Pole_Full_Sine = 0x03


@register_entity(INOVELLI_CLUSTER)
class InovelliSwitchTypeEntity(ZCLEnumSelectEntity):
    """Inovelli switch type control."""

    _unique_id_suffix = "switch_type"
    _attribute_name = "switch_type"
    _enum = InovelliSwitchType
    _attr_translation_key: str = "switch_type"

    _cluster_handler_match = ClusterHandlerMatch(
        cluster_handlers=frozenset({CLUSTER_HANDLER_INOVELLI}),
        models=frozenset({"VZM31-SN"}),
    )


class InovelliFanSwitchType(types.enum1):
    """Inovelli fan switch mode."""

    Load_Only = 0x00
    Three_Way_AUX = 0x01


@register_entity(INOVELLI_CLUSTER)
class InovelliFanSwitchTypeEntity(ZCLEnumSelectEntity):
    """Inovelli fan switch type control."""

    _unique_id_suffix = "switch_type"
    _attribute_name = "switch_type"
    _enum = InovelliFanSwitchType
    _attr_translation_key: str = "switch_type"

    _cluster_handler_match = ClusterHandlerMatch(
        cluster_handlers=frozenset({CLUSTER_HANDLER_INOVELLI}),
        models=frozenset({"VZM35-SN"}),
    )


class InovelliLedScalingMode(types.enum1):
    """Inovelli led mode."""

    VZM31SN = 0x00
    LZW31SN = 0x01


@register_entity(INOVELLI_CLUSTER)
class InovelliLedScalingModeEntity(ZCLEnumSelectEntity):
    """Inovelli led mode control."""

    _unique_id_suffix = "led_scaling_mode"
    _attribute_name = "led_scaling_mode"
    _enum = InovelliLedScalingMode
    _attr_translation_key: str = "led_scaling_mode"

    _cluster_handler_match = ClusterHandlerMatch(
        cluster_handlers=frozenset({CLUSTER_HANDLER_INOVELLI})
    )


class InovelliFanLedScalingMode(types.enum8):
    """Inovelli fan led mode."""

    VZM31SN = 0x00
    Grade_1 = 0x01
    Grade_2 = 0x02
    Grade_3 = 0x03
    Grade_4 = 0x04
    Grade_5 = 0x05
    Grade_6 = 0x06
    Grade_7 = 0x07
    Grade_8 = 0x08
    Grade_9 = 0x09
    Adaptive = 0x0A


@register_entity(INOVELLI_CLUSTER)
class InovelliFanLedScalingModeEntity(ZCLEnumSelectEntity):
    """Inovelli fan switch led mode control."""

    _unique_id_suffix = "smart_fan_led_display_levels"
    _attribute_name = "smart_fan_led_display_levels"
    _enum = InovelliFanLedScalingMode
    _attr_translation_key: str = "smart_fan_led_display_levels"

    _cluster_handler_match = ClusterHandlerMatch(
        cluster_handlers=frozenset({CLUSTER_HANDLER_INOVELLI}),
        models=frozenset({"VZM35-SN"}),
    )


class InovelliNonNeutralOutput(types.enum1):
    """Inovelli non neutral output selection."""

    Low = 0x00
    High = 0x01


@register_entity(INOVELLI_CLUSTER)
class InovelliNonNeutralOutputEntity(ZCLEnumSelectEntity):
    """Inovelli non neutral output control."""

    _unique_id_suffix = "increased_non_neutral_output"
    _attribute_name = "increased_non_neutral_output"
    _enum = InovelliNonNeutralOutput
    _attr_translation_key: str = "increased_non_neutral_output"

    _cluster_handler_match = ClusterHandlerMatch(
        cluster_handlers=frozenset({CLUSTER_HANDLER_INOVELLI})
    )


class InovelliDimmingMode(types.enum1):
    """Inovelli dimming mode selection."""

    LeadingEdge = 0x00
    TrailingEdge = 0x01


@register_entity(INOVELLI_CLUSTER)
class InovelliDimmingModeEntity(ZCLEnumSelectEntity):
    """Inovelli dimming mode control."""

    _unique_id_suffix = "leading_or_trailing_edge"
    _attribute_name = "leading_or_trailing_edge"
    _enum = InovelliDimmingMode
    _attr_translation_key: str = "leading_or_trailing_edge"

    _cluster_handler_match = ClusterHandlerMatch(
        cluster_handlers=frozenset({CLUSTER_HANDLER_INOVELLI}),
        models=frozenset({"VZM31-SN", "VZM36"}),
    )


class AqaraFeedingMode(types.enum8):
    """Feeding mode."""

    Manual = 0x00
    Schedule = 0x01


@register_entity(AQARA_OPPLE_CLUSTER)
class AqaraPetFeederMode(ZCLEnumSelectEntity):
    """Representation of an Aqara pet feeder mode configuration entity."""

    _unique_id_suffix = "feeding_mode"
    _attribute_name = "feeding_mode"
    _enum = AqaraFeedingMode
    _attr_translation_key: str = "feeding_mode"

    _cluster_handler_match = ClusterHandlerMatch(
        cluster_handlers=frozenset({"opple_cluster"}),
        models=frozenset({"aqara.feeder.acn001"}),
    )


class AqaraThermostatPresetMode(types.enum8):
    """Thermostat preset mode."""

    Manual = 0x00
    Auto = 0x01
    Away = 0x02


@register_entity(AQARA_OPPLE_CLUSTER)
class AqaraThermostatPreset(ZCLEnumSelectEntity):
    """Representation of an Aqara thermostat preset configuration entity."""

    _unique_id_suffix = "preset"
    _attribute_name = "preset"
    _enum = AqaraThermostatPresetMode
    _attr_translation_key: str = "preset"

    _cluster_handler_match = ClusterHandlerMatch(
        cluster_handlers=frozenset({"opple_cluster"}),
        models=frozenset({"lumi.airrtc.agl001"}),
    )


class SonoffPresenceDetectionSensitivityEnum(types.enum8):
    """Enum for detection sensitivity select entity."""

    Low = 0x01
    Medium = 0x02
    High = 0x03


@register_entity(OccupancySensing.cluster_id)
class SonoffPresenceDetectionSensitivity(ZCLEnumSelectEntity):
    """Entity to set the detection sensitivity of the Sonoff SNZB-06P."""

    _unique_id_suffix = "detection_sensitivity"
    _attribute_name = "ultrasonic_u_to_o_threshold"
    _enum = SonoffPresenceDetectionSensitivityEnum
    _attr_translation_key: str = "detection_sensitivity"

    _cluster_handler_match = ClusterHandlerMatch(
        cluster_handlers=frozenset({CLUSTER_HANDLER_OCCUPANCY}),
        models=frozenset({"SNZB-06P", "SNZB-03P"}),
    )


class KeypadLockoutEnum(types.enum8):
    """Keypad lockout options."""

    Unlock = 0x00
    Lock1 = 0x01
    Lock2 = 0x02
    Lock3 = 0x03
    Lock4 = 0x04


@register_entity(UserInterface.cluster_id)
class KeypadLockout(ZCLEnumSelectEntity):
    """Mandatory attribute for thermostat_ui cluster.

    Often only the first two are implemented, and Lock2 to Lock4 should map to Lock1 in the firmware.
    This however covers all bases.
    """

    _unique_id_suffix = "keypad_lockout"
    _attribute_name: str = "keypad_lockout"
    _enum = KeypadLockoutEnum
    _attr_translation_key: str = "keypad_lockout"

    _cluster_handler_match = ClusterHandlerMatch(
        cluster_handlers=frozenset({"thermostat_ui"})
    )


@register_entity(Thermostat.cluster_id)
class DanfossExerciseDayOfTheWeek(ZCLEnumSelectEntity):
    """Danfoss proprietary attribute for setting the day of the week for exercising."""

    _unique_id_suffix = "exercise_day_of_week"
    _attribute_name = "exercise_day_of_week"
    _attr_translation_key: str = "exercise_day_of_week"
    _enum = danfoss_thermostat.DanfossExerciseDayOfTheWeekEnum

    _cluster_handler_match = ClusterHandlerMatch(
        cluster_handlers=frozenset({CLUSTER_HANDLER_THERMOSTAT}),
        exposed_features=frozenset({DANFOSS_ALLY_THERMOSTAT}),
    )


class DanfossOrientationEnum(types.enum8):
    """Vertical or Horizontal."""

    Horizontal = 0x00
    Vertical = 0x01


@register_entity(Thermostat.cluster_id)
class DanfossOrientation(ZCLEnumSelectEntity):
    """Danfoss proprietary attribute for setting the orientation of the valve.

    Needed for biasing the internal temperature sensor.
    This is implemented as an enum here, but is a boolean on the device.
    """

    _unique_id_suffix = "orientation"
    _attribute_name = "orientation"
    _attr_translation_key: str = "valve_orientation"
    _enum = DanfossOrientationEnum

    _cluster_handler_match = ClusterHandlerMatch(
        cluster_handlers=frozenset({CLUSTER_HANDLER_THERMOSTAT}),
        exposed_features=frozenset({DANFOSS_ALLY_THERMOSTAT}),
    )


@register_entity(Thermostat.cluster_id)
class DanfossAdaptationRunControl(ZCLEnumSelectEntity):
    """Danfoss proprietary attribute for controlling the current adaptation run."""

    _unique_id_suffix = "adaptation_run_control"
    _attribute_name = "adaptation_run_control"
    _attr_translation_key: str = "adaptation_run_command"
    _enum = danfoss_thermostat.DanfossAdaptationRunControlEnum

    _cluster_handler_match = ClusterHandlerMatch(
        cluster_handlers=frozenset({CLUSTER_HANDLER_THERMOSTAT}),
        exposed_features=frozenset({DANFOSS_ALLY_THERMOSTAT}),
    )


class DanfossControlAlgorithmScaleFactorEnum(types.enum8):
    """The time scale factor for changing the opening of the valve.

    Not all values are given, therefore there are some extrapolated values with a margin of error of about 5 minutes.
    This is implemented as an enum here, but is a number on the device.
    """

    quick_5min = 0x01

    quick_10min = 0x02  # extrapolated
    quick_15min = 0x03  # extrapolated
    quick_25min = 0x04  # extrapolated

    moderate_30min = 0x05

    moderate_40min = 0x06  # extrapolated
    moderate_50min = 0x07  # extrapolated
    moderate_60min = 0x08  # extrapolated
    moderate_70min = 0x09  # extrapolated

    slow_80min = 0x0A

    quick_open_disabled = 0x11  # not sure what it does; also requires lower 4 bits to be in [1, 10] I assume


@register_entity(Thermostat.cluster_id)
class DanfossControlAlgorithmScaleFactor(ZCLEnumSelectEntity):
    """Danfoss proprietary attribute for setting the scale factor of the setpoint filter time constant."""

    _unique_id_suffix = "control_algorithm_scale_factor"
    _attribute_name = "control_algorithm_scale_factor"
    _attr_translation_key: str = "setpoint_response_time"
    _enum = DanfossControlAlgorithmScaleFactorEnum

    _cluster_handler_match = ClusterHandlerMatch(
        cluster_handlers=frozenset({CLUSTER_HANDLER_THERMOSTAT}),
        exposed_features=frozenset({DANFOSS_ALLY_THERMOSTAT}),
    )


@register_entity(UserInterface.cluster_id)
class DanfossViewingDirection(ZCLEnumSelectEntity):
    """Danfoss proprietary attribute for setting the viewing direction of the screen."""

    _unique_id_suffix = "viewing_direction"
    _attribute_name = "viewing_direction"
    _attr_translation_key: str = "viewing_direction"
    _enum = danfoss_thermostat.DanfossViewingDirectionEnum

    _cluster_handler_match = ClusterHandlerMatch(
        cluster_handlers=frozenset({"thermostat_ui"}),
        exposed_features=frozenset({DANFOSS_ALLY_THERMOSTAT}),
    )


class SinopeLightLedColors(types.enum32):
    """Color values for Sinope light switch status LEDs."""

    Lim = 0x0AFFDC
    Amber = 0x000A4B
    Fushia = 0x0100A5
    Perle = 0x64FFFF
    Blue = 0xFFFF00


SINOPE_MODELS = frozenset(
    {
        "DM2500ZB",
        "DM2500ZB-G2",
        "DM2550ZB",
        "DM2550ZB-G2",
        "SW2500ZB",
        "SW2500ZB-G2",
    }
)


@register_entity(SINOPE_MANUFACTURER_CLUSTER)
class SinopeLightLEDOffColorSelect(ZCLEnumSelectEntity):
    """Representation of the marker LED Off-state color of Sinope light switches."""

    _unique_id_suffix = "off_led_color"
    _attribute_name = "off_led_color"
    _attr_translation_key: str = "off_led_color"
    _enum = SinopeLightLedColors

    _cluster_handler_match = ClusterHandlerMatch(
        cluster_handlers=frozenset({"sinope_manufacturer_specific"}),
        models=SINOPE_MODELS,
    )


@register_entity(SINOPE_MANUFACTURER_CLUSTER)
class SinopeLightLEDOnColorSelect(ZCLEnumSelectEntity):
    """Representation of the marker LED On-state color of Sinope light switches."""

    _unique_id_suffix = "on_led_color"
    _attribute_name = "on_led_color"
    _attr_translation_key: str = "on_led_color"
    _enum = SinopeLightLedColors

    _cluster_handler_match = ClusterHandlerMatch(
        cluster_handlers=frozenset({"sinope_manufacturer_specific"}),
        models=SINOPE_MODELS,
    )
