"""Provides a light for Home Connect."""

from dataclasses import dataclass
import logging
from typing import Any, cast

from aiohomeconnect.model import EventKey, SettingKey
from aiohomeconnect.model.error import HomeConnectError

from homeassistant.components.light import (
    ATTR_BRIGHTNESS,
    ATTR_HS_COLOR,
    ATTR_RGB_COLOR,
    ColorMode,
    LightEntity,
    LightEntityDescription,
)
from homeassistant.core import HomeAssistant
from homeassistant.exceptions import HomeAssistantError
from homeassistant.helpers.entity_platform import AddConfigEntryEntitiesCallback
from homeassistant.util import color as color_util

from .common import setup_home_connect_entry
from .const import BSH_AMBIENT_LIGHT_COLOR_CUSTOM_COLOR, DOMAIN
from .coordinator import (
    HomeConnectApplianceData,
    HomeConnectConfigEntry,
    HomeConnectCoordinator,
)
from .entity import HomeConnectEntity
from .utils import get_dict_from_home_connect_error

_LOGGER = logging.getLogger(__name__)

PARALLEL_UPDATES = 1


@dataclass(frozen=True, kw_only=True)
class HomeConnectLightEntityDescription(LightEntityDescription):
    """Light entity description."""

    brightness_key: SettingKey
    brightness_scale: tuple[float, float]
    color_key: SettingKey | None = None
    enable_custom_color_value_key: str | None = None
    custom_color_key: SettingKey | None = None


LIGHTS: tuple[HomeConnectLightEntityDescription, ...] = (
    HomeConnectLightEntityDescription(
        key=SettingKey.REFRIGERATION_COMMON_LIGHT_INTERNAL_POWER,
        brightness_key=SettingKey.REFRIGERATION_COMMON_LIGHT_INTERNAL_BRIGHTNESS,
        brightness_scale=(1.0, 100.0),
        translation_key="internal_light",
    ),
    HomeConnectLightEntityDescription(
        key=SettingKey.REFRIGERATION_COMMON_LIGHT_EXTERNAL_POWER,
        brightness_key=SettingKey.REFRIGERATION_COMMON_LIGHT_EXTERNAL_BRIGHTNESS,
        brightness_scale=(1.0, 100.0),
        translation_key="external_light",
    ),
    HomeConnectLightEntityDescription(
        key=SettingKey.COOKING_COMMON_LIGHTING,
        brightness_key=SettingKey.COOKING_COMMON_LIGHTING_BRIGHTNESS,
        brightness_scale=(10.0, 100.0),
        translation_key="cooking_lighting",
    ),
    HomeConnectLightEntityDescription(
        key=SettingKey.BSH_COMMON_AMBIENT_LIGHT_ENABLED,
        brightness_key=SettingKey.BSH_COMMON_AMBIENT_LIGHT_BRIGHTNESS,
        color_key=SettingKey.BSH_COMMON_AMBIENT_LIGHT_COLOR,
        enable_custom_color_value_key=BSH_AMBIENT_LIGHT_COLOR_CUSTOM_COLOR,
        custom_color_key=SettingKey.BSH_COMMON_AMBIENT_LIGHT_CUSTOM_COLOR,
        brightness_scale=(10.0, 100.0),
        translation_key="ambient_light",
    ),
)


def _get_entities_for_appliance(
    entry: HomeConnectConfigEntry,
    appliance: HomeConnectApplianceData,
) -> list[HomeConnectEntity]:
    """Get a list of entities."""
    return [
        HomeConnectLight(entry.runtime_data, appliance, description)
        for description in LIGHTS
        if description.key in appliance.settings
    ]


async def async_setup_entry(
    hass: HomeAssistant,
    entry: HomeConnectConfigEntry,
    async_add_entities: AddConfigEntryEntitiesCallback,
) -> None:
    """Set up the Home Connect light."""
    setup_home_connect_entry(
        entry,
        _get_entities_for_appliance,
        async_add_entities,
    )


class HomeConnectLight(HomeConnectEntity, LightEntity):
    """Light for Home Connect."""

    entity_description: LightEntityDescription

    def __init__(
        self,
        coordinator: HomeConnectCoordinator,
        appliance: HomeConnectApplianceData,
        desc: HomeConnectLightEntityDescription,
    ) -> None:
        """Initialize the entity."""

        def get_setting_key_if_setting_exists(
            setting_key: SettingKey | None,
        ) -> SettingKey | None:
            if setting_key and setting_key in appliance.settings:
                return setting_key
            return None

        self._brightness_key = get_setting_key_if_setting_exists(desc.brightness_key)
        self._custom_color_key = get_setting_key_if_setting_exists(
            desc.custom_color_key
        )
        self._color_key = get_setting_key_if_setting_exists(desc.color_key)
        self._enable_custom_color_value_key = desc.enable_custom_color_value_key
        self._custom_color_key = get_setting_key_if_setting_exists(
            desc.custom_color_key
        )
        self._brightness_scale = desc.brightness_scale

        super().__init__(coordinator, appliance, desc)

        match (self._brightness_key, self._custom_color_key):
            case (None, None):
                self._attr_color_mode = ColorMode.ONOFF
                self._attr_supported_color_modes = {ColorMode.ONOFF}
            case (_, None):
                self._attr_color_mode = ColorMode.BRIGHTNESS
                self._attr_supported_color_modes = {ColorMode.BRIGHTNESS}
            case (_, _):
                self._attr_color_mode = ColorMode.HS
                self._attr_supported_color_modes = {ColorMode.HS, ColorMode.RGB}

    async def async_turn_on(self, **kwargs: Any) -> None:
        """Switch the light on, change brightness, change color."""
        try:
            await self.coordinator.client.set_setting(
                self.appliance.info.ha_id,
                setting_key=SettingKey(self.bsh_key),
                value=True,
            )
        except HomeConnectError as err:
            raise HomeAssistantError(
                translation_domain=DOMAIN,
                translation_key="turn_on_light",
                translation_placeholders={
                    **get_dict_from_home_connect_error(err),
                    "entity_id": self.entity_id,
                },
            ) from err
        if self._color_key and self._custom_color_key:
            if (
                ATTR_RGB_COLOR in kwargs or ATTR_HS_COLOR in kwargs
            ) and self._enable_custom_color_value_key:
                try:
                    await self.coordinator.client.set_setting(
                        self.appliance.info.ha_id,
                        setting_key=self._color_key,
                        value=self._enable_custom_color_value_key,
                    )
                except HomeConnectError as err:
                    raise HomeAssistantError(
                        translation_domain=DOMAIN,
                        translation_key="select_light_custom_color",
                        translation_placeholders={
                            **get_dict_from_home_connect_error(err),
                            "entity_id": self.entity_id,
                        },
                    ) from err

            if ATTR_RGB_COLOR in kwargs:
                hex_val = color_util.color_rgb_to_hex(*kwargs[ATTR_RGB_COLOR])
                try:
                    await self.coordinator.client.set_setting(
                        self.appliance.info.ha_id,
                        setting_key=self._custom_color_key,
                        value=f"#{hex_val}",
                    )
                except HomeConnectError as err:
                    raise HomeAssistantError(
                        translation_domain=DOMAIN,
                        translation_key="set_light_color",
                        translation_placeholders={
                            **get_dict_from_home_connect_error(err),
                            "entity_id": self.entity_id,
                        },
                    ) from err
                return
            if (self._attr_brightness is not None or ATTR_BRIGHTNESS in kwargs) and (
                self._attr_hs_color is not None or ATTR_HS_COLOR in kwargs
            ):
                brightness = round(
                    color_util.brightness_to_value(
                        self._brightness_scale,
                        cast(int, kwargs.get(ATTR_BRIGHTNESS, self._attr_brightness)),
                    )
                )

                hs_color = cast(
                    tuple[float, float], kwargs.get(ATTR_HS_COLOR, self._attr_hs_color)
                )

                rgb = color_util.color_hsv_to_RGB(hs_color[0], hs_color[1], brightness)
                hex_val = color_util.color_rgb_to_hex(*rgb)
                try:
                    await self.coordinator.client.set_setting(
                        self.appliance.info.ha_id,
                        setting_key=self._custom_color_key,
                        value=f"#{hex_val}",
                    )
                except HomeConnectError as err:
                    raise HomeAssistantError(
                        translation_domain=DOMAIN,
                        translation_key="set_light_color",
                        translation_placeholders={
                            **get_dict_from_home_connect_error(err),
                            "entity_id": self.entity_id,
                        },
                    ) from err
                return

        if self._brightness_key and ATTR_BRIGHTNESS in kwargs:
            brightness = round(
                color_util.brightness_to_value(
                    self._brightness_scale, kwargs[ATTR_BRIGHTNESS]
                )
            )
            try:
                await self.coordinator.client.set_setting(
                    self.appliance.info.ha_id,
                    setting_key=self._brightness_key,
                    value=brightness,
                )
            except HomeConnectError as err:
                raise HomeAssistantError(
                    translation_domain=DOMAIN,
                    translation_key="set_light_brightness",
                    translation_placeholders={
                        **get_dict_from_home_connect_error(err),
                        "entity_id": self.entity_id,
                    },
                ) from err

    async def async_turn_off(self, **kwargs: Any) -> None:
        """Switch the light off."""
        try:
            await self.coordinator.client.set_setting(
                self.appliance.info.ha_id,
                setting_key=SettingKey(self.bsh_key),
                value=False,
            )
        except HomeConnectError as err:
            raise HomeAssistantError(
                translation_domain=DOMAIN,
                translation_key="turn_off_light",
                translation_placeholders={
                    **get_dict_from_home_connect_error(err),
                    "entity_id": self.entity_id,
                },
            ) from err

    async def async_added_to_hass(self) -> None:
        """Register listener."""
        await super().async_added_to_hass()
        keys_to_listen = []
        if self._brightness_key:
            keys_to_listen.append(self._brightness_key)
        if self._color_key and self._custom_color_key:
            keys_to_listen.extend([self._color_key, self._custom_color_key])
        for key in keys_to_listen:
            self.async_on_remove(
                self.coordinator.async_add_listener(
                    self._handle_coordinator_update,
                    (
                        self.appliance.info.ha_id,
                        EventKey(key),
                    ),
                )
            )

    def update_native_value(self) -> None:
        """Update the light's status."""
        self._attr_is_on = self.appliance.settings[SettingKey(self.bsh_key)].value

        if self._brightness_key:
            brightness = cast(
                float, self.appliance.settings[self._brightness_key].value
            )
            self._attr_brightness = color_util.value_to_brightness(
                self._brightness_scale, brightness
            )
            _LOGGER.debug(
                "Updated %s, new brightness: %s", self.entity_id, self._attr_brightness
            )
        if self._color_key and self._custom_color_key:
            color = cast(str, self.appliance.settings[self._color_key].value)
            if color != self._enable_custom_color_value_key:
                self._attr_rgb_color = None
                self._attr_hs_color = None
            else:
                custom_color = cast(
                    str, self.appliance.settings[self._custom_color_key].value
                )
                color_value = custom_color[1:]
                rgb = color_util.rgb_hex_to_rgb_list(color_value)
                self._attr_rgb_color = (rgb[0], rgb[1], rgb[2])
                hsv = color_util.color_RGB_to_hsv(*rgb)
                self._attr_hs_color = (hsv[0], hsv[1])
                self._attr_brightness = color_util.value_to_brightness(
                    self._brightness_scale, hsv[2]
                )
                _LOGGER.debug(
                    "Updated %s, new color (%s) and new brightness (%s) ",
                    self.entity_id,
                    color_value,
                    self._attr_brightness,
                )
