"""Support for select entities."""

from dataclasses import dataclass, field
from enum import IntEnum
from typing import override

from gardena_bluetooth.const import (
    AquaContour,
    AquaContourPosition,
    AquaContourWatering,
)
from gardena_bluetooth.parse import CharacteristicInt

from homeassistant.components.select import SelectEntity, SelectEntityDescription
from homeassistant.const import EntityCategory
from homeassistant.core import HomeAssistant
from homeassistant.helpers.entity_platform import AddConfigEntryEntitiesCallback

from .coordinator import GardenaBluetoothConfigEntry
from .entity import GardenaBluetoothDescriptorEntity


def _enum_to_int(enum: type[IntEnum]) -> dict[str, int]:
    return {member.name.lower(): member.value for member in enum}


def _reverse_dict(value: dict[str, int]) -> dict[int, str]:
    return {value: key for key, value in value.items()}


@dataclass(frozen=True, kw_only=True)
class GardenaBluetoothSelectEntityDescription(SelectEntityDescription):
    """Description of entity."""

    key: str = field(init=False)
    char: CharacteristicInt
    option_to_number: dict[str, int]
    number_to_option: dict[int, str] = field(init=False)

    def __post_init__(self):
        """Initialize calculated fields."""
        object.__setattr__(self, "key", self.char.unique_id)
        object.__setattr__(self, "options", list(self.option_to_number.keys()))
        object.__setattr__(
            self, "number_to_option", _reverse_dict(self.option_to_number)
        )

    @property
    def context(self) -> set[str]:
        """Context needed for update coordinator."""
        return {self.char.uuid}


DESCRIPTIONS = (
    GardenaBluetoothSelectEntityDescription(
        translation_key="watering_active",
        char=AquaContourWatering.watering_active,
        option_to_number=_enum_to_int(AquaContourWatering.watering_active.enum),
    ),
    GardenaBluetoothSelectEntityDescription(
        translation_key="operation_mode",
        char=AquaContour.operation_mode,
        option_to_number=_enum_to_int(AquaContour.operation_mode.enum),
        entity_category=EntityCategory.CONFIG,
    ),
    GardenaBluetoothSelectEntityDescription(
        translation_key="active_position",
        char=AquaContourPosition.active_position,
        option_to_number={
            "position_1": 1,
            "position_2": 2,
            "position_3": 3,
            "position_4": 4,
            "position_5": 5,
        },
    ),
)


async def async_setup_entry(
    hass: HomeAssistant,
    entry: GardenaBluetoothConfigEntry,
    async_add_entities: AddConfigEntryEntitiesCallback,
) -> None:
    """Set up select based on a config entry."""
    coordinator = entry.runtime_data
    entities = [
        GardenaBluetoothSelectEntity(coordinator, description, description.context)
        for description in DESCRIPTIONS
        if description.char.unique_id in coordinator.characteristics
    ]
    async_add_entities(entities)


class GardenaBluetoothSelectEntity(GardenaBluetoothDescriptorEntity, SelectEntity):
    """Representation of a select entity."""

    entity_description: GardenaBluetoothSelectEntityDescription

    @property
    @override
    def current_option(self) -> str | None:
        """Return the selected entity option to represent the entity state."""
        char = self.entity_description.char
        value = self.coordinator.get_cached(char)
        if value is None:
            return None
        return self.entity_description.number_to_option.get(value)

    @override
    async def async_select_option(self, option: str) -> None:
        """Change the selected option."""
        char = self.entity_description.char
        value = self.entity_description.option_to_number[option]
        await self.coordinator.write(char, value)
        self.async_write_ha_state()
