"""Select platform for Indevolt integration."""

from dataclasses import dataclass, field
from typing import Final, override

from indevolt_api import IndevoltConfig, IndevoltEnergyMode

from homeassistant.components.select import SelectEntity, SelectEntityDescription
from homeassistant.core import HomeAssistant
from homeassistant.exceptions import HomeAssistantError
from homeassistant.helpers.entity_platform import AddConfigEntryEntitiesCallback

from . import IndevoltConfigEntry
from .const import DOMAIN
from .coordinator import IndevoltCoordinator
from .entity import IndevoltEntity

PARALLEL_UPDATES = 0


@dataclass(frozen=True, kw_only=True)
class IndevoltSelectEntityDescription(SelectEntityDescription):
    """Custom entity description class for Indevolt select entities."""

    read_key: str
    write_key: str
    value_to_option: dict[IndevoltEnergyMode, str]
    unavailable_values: list[IndevoltEnergyMode] = field(default_factory=list)
    generation: tuple[int, ...] = (1, 2)


SELECTS: Final = (
    IndevoltSelectEntityDescription(
        key="energy_mode",
        translation_key="energy_mode",
        read_key=IndevoltConfig.READ_ENERGY_MODE,
        write_key=IndevoltConfig.WRITE_ENERGY_MODE,
        value_to_option={
            IndevoltEnergyMode.SELF_CONSUMED_PRIORITIZED: "self_consumed_prioritized",
            IndevoltEnergyMode.REAL_TIME_CONTROL: "real_time_control",
            IndevoltEnergyMode.CHARGE_DISCHARGE_SCHEDULE: "charge_discharge_schedule",
        },
        unavailable_values=[IndevoltEnergyMode.OUTDOOR_PORTABLE],
    ),
)


async def async_setup_entry(
    hass: HomeAssistant,
    entry: IndevoltConfigEntry,
    async_add_entities: AddConfigEntryEntitiesCallback,
) -> None:
    """Set up the select platform for Indevolt."""
    coordinator = entry.runtime_data
    device_gen = coordinator.generation

    # Select initialization
    async_add_entities(
        IndevoltSelectEntity(coordinator=coordinator, description=description)
        for description in SELECTS
        if device_gen in description.generation
    )


class IndevoltSelectEntity(IndevoltEntity, SelectEntity):
    """Represents a select entity for Indevolt devices."""

    entity_description: IndevoltSelectEntityDescription

    def __init__(
        self,
        coordinator: IndevoltCoordinator,
        description: IndevoltSelectEntityDescription,
    ) -> None:
        """Initialize the Indevolt select entity."""
        super().__init__(coordinator)

        self.entity_description = description
        self._attr_unique_id = f"{self.serial_number}_{description.key}"
        self._attr_options = list(description.value_to_option.values())
        self._option_to_value = {v: k for k, v in description.value_to_option.items()}

    @property
    @override
    def current_option(self) -> str | None:
        """Return the currently selected option."""
        raw_value = self.coordinator.data.get(self.entity_description.read_key)
        if raw_value is None:
            return None

        return self.entity_description.value_to_option.get(raw_value)

    @property
    @override
    def available(self) -> bool:
        """Return False when the device is in a mode that cannot be selected."""
        if not super().available:
            return False

        raw_value = self.coordinator.data.get(self.entity_description.read_key)
        return raw_value not in self.entity_description.unavailable_values

    @override
    async def async_select_option(self, option: str) -> None:
        """Select a new option."""
        value = self._option_to_value[option]
        success = await self.coordinator.async_push_data(
            self.entity_description.write_key, value
        )

        if success:
            self.coordinator.async_optimistic_update(
                self.entity_description.read_key, value
            )

        else:
            raise HomeAssistantError(
                translation_domain=DOMAIN,
                translation_key="write_error",
                translation_placeholders={"name": str(self.name)},
            )
