"""Support for HomematicIP Cloud lights."""
from __future__ import annotations

from typing import Any

from homematicip.aio.device import (
    AsyncBrandDimmer,
    AsyncBrandSwitchMeasuring,
    AsyncBrandSwitchNotificationLight,
    AsyncDimmer,
    AsyncDinRailDimmer3,
    AsyncFullFlushDimmer,
    AsyncPluggableDimmer,
    AsyncWiredDimmer3,
)
from homematicip.base.enums import RGBColorState
from homematicip.base.functionalChannels import NotificationLightChannel

from homeassistant.components.light import (
    ATTR_BRIGHTNESS,
    ATTR_COLOR_NAME,
    ATTR_HS_COLOR,
    ATTR_TRANSITION,
    ColorMode,
    LightEntity,
    LightEntityFeature,
)
from homeassistant.config_entries import ConfigEntry
from homeassistant.core import HomeAssistant
from homeassistant.helpers.entity_platform import AddEntitiesCallback

from . import DOMAIN as HMIPC_DOMAIN, HomematicipGenericEntity
from .hap import HomematicipHAP


async def async_setup_entry(
    hass: HomeAssistant,
    config_entry: ConfigEntry,
    async_add_entities: AddEntitiesCallback,
) -> None:
    """Set up the HomematicIP Cloud lights from a config entry."""
    hap = hass.data[HMIPC_DOMAIN][config_entry.unique_id]
    entities: list[HomematicipGenericEntity] = []
    for device in hap.home.devices:
        if isinstance(device, AsyncBrandSwitchMeasuring):
            entities.append(HomematicipLightMeasuring(hap, device))
        elif isinstance(device, AsyncBrandSwitchNotificationLight):
            entities.append(HomematicipLight(hap, device))
            entities.append(
                HomematicipNotificationLight(hap, device, device.topLightChannelIndex)
            )
            entities.append(
                HomematicipNotificationLight(
                    hap, device, device.bottomLightChannelIndex
                )
            )
        elif isinstance(device, (AsyncWiredDimmer3, AsyncDinRailDimmer3)):
            for channel in range(1, 4):
                entities.append(HomematicipMultiDimmer(hap, device, channel=channel))
        elif isinstance(
            device,
            (AsyncDimmer, AsyncPluggableDimmer, AsyncBrandDimmer, AsyncFullFlushDimmer),
        ):
            entities.append(HomematicipDimmer(hap, device))

    async_add_entities(entities)


class HomematicipLight(HomematicipGenericEntity, LightEntity):
    """Representation of the HomematicIP light."""

    _attr_color_mode = ColorMode.ONOFF
    _attr_supported_color_modes = {ColorMode.ONOFF}

    def __init__(self, hap: HomematicipHAP, device) -> None:
        """Initialize the light entity."""
        super().__init__(hap, device)

    @property
    def is_on(self) -> bool:
        """Return true if light is on."""
        return self._device.on

    async def async_turn_on(self, **kwargs: Any) -> None:
        """Turn the light on."""
        await self._device.turn_on()

    async def async_turn_off(self, **kwargs: Any) -> None:
        """Turn the light off."""
        await self._device.turn_off()


class HomematicipLightMeasuring(HomematicipLight):
    """Representation of the HomematicIP measuring light."""


class HomematicipMultiDimmer(HomematicipGenericEntity, LightEntity):
    """Representation of HomematicIP Cloud dimmer."""

    _attr_color_mode = ColorMode.BRIGHTNESS
    _attr_supported_color_modes = {ColorMode.BRIGHTNESS}

    def __init__(
        self,
        hap: HomematicipHAP,
        device,
        channel=1,
        is_multi_channel=True,
    ) -> None:
        """Initialize the dimmer light entity."""
        super().__init__(
            hap, device, channel=channel, is_multi_channel=is_multi_channel
        )

    @property
    def is_on(self) -> bool:
        """Return true if dimmer is on."""
        func_channel = self._device.functionalChannels[self._channel]
        return func_channel.dimLevel is not None and func_channel.dimLevel > 0.0

    @property
    def brightness(self) -> int:
        """Return the brightness of this light between 0..255."""
        return int(
            (self._device.functionalChannels[self._channel].dimLevel or 0.0) * 255
        )

    async def async_turn_on(self, **kwargs: Any) -> None:
        """Turn the dimmer on."""
        if ATTR_BRIGHTNESS in kwargs:
            await self._device.set_dim_level(
                kwargs[ATTR_BRIGHTNESS] / 255.0, self._channel
            )
        else:
            await self._device.set_dim_level(1, self._channel)

    async def async_turn_off(self, **kwargs: Any) -> None:
        """Turn the dimmer off."""
        await self._device.set_dim_level(0, self._channel)


class HomematicipDimmer(HomematicipMultiDimmer, LightEntity):
    """Representation of HomematicIP Cloud dimmer."""

    def __init__(self, hap: HomematicipHAP, device) -> None:
        """Initialize the dimmer light entity."""
        super().__init__(hap, device, is_multi_channel=False)


class HomematicipNotificationLight(HomematicipGenericEntity, LightEntity):
    """Representation of HomematicIP Cloud notification light."""

    _attr_color_mode = ColorMode.HS
    _attr_supported_color_modes = {ColorMode.HS}
    _attr_supported_features = LightEntityFeature.TRANSITION

    def __init__(self, hap: HomematicipHAP, device, channel: int) -> None:
        """Initialize the notification light entity."""
        if channel == 2:
            super().__init__(
                hap, device, post="Top", channel=channel, is_multi_channel=True
            )
        else:
            super().__init__(
                hap, device, post="Bottom", channel=channel, is_multi_channel=True
            )

        self._color_switcher: dict[str, tuple[float, float]] = {
            RGBColorState.WHITE: (0.0, 0.0),
            RGBColorState.RED: (0.0, 100.0),
            RGBColorState.YELLOW: (60.0, 100.0),
            RGBColorState.GREEN: (120.0, 100.0),
            RGBColorState.TURQUOISE: (180.0, 100.0),
            RGBColorState.BLUE: (240.0, 100.0),
            RGBColorState.PURPLE: (300.0, 100.0),
        }

    @property
    def _func_channel(self) -> NotificationLightChannel:
        return self._device.functionalChannels[self._channel]

    @property
    def is_on(self) -> bool:
        """Return true if light is on."""
        return (
            self._func_channel.dimLevel is not None
            and self._func_channel.dimLevel > 0.0
        )

    @property
    def brightness(self) -> int:
        """Return the brightness of this light between 0..255."""
        return int((self._func_channel.dimLevel or 0.0) * 255)

    @property
    def hs_color(self) -> tuple[float, float]:
        """Return the hue and saturation color value [float, float]."""
        simple_rgb_color = self._func_channel.simpleRGBColorState
        return self._color_switcher.get(simple_rgb_color, (0.0, 0.0))

    @property
    def extra_state_attributes(self) -> dict[str, Any]:
        """Return the state attributes of the notification light sensor."""
        state_attr = super().extra_state_attributes

        if self.is_on:
            state_attr[ATTR_COLOR_NAME] = self._func_channel.simpleRGBColorState

        return state_attr

    @property
    def unique_id(self) -> str:
        """Return a unique ID."""
        return f"{self.__class__.__name__}_{self._post}_{self._device.id}"

    async def async_turn_on(self, **kwargs: Any) -> None:
        """Turn the light on."""
        # Use hs_color from kwargs,
        # if not applicable use current hs_color.
        hs_color = kwargs.get(ATTR_HS_COLOR, self.hs_color)
        simple_rgb_color = _convert_color(hs_color)

        # Use brightness from kwargs,
        # if not applicable use current brightness.
        brightness = kwargs.get(ATTR_BRIGHTNESS, self.brightness)

        # If no kwargs, use default value.
        if not kwargs:
            brightness = 255

        # Minimum brightness is 10, otherwise the led is disabled
        brightness = max(10, brightness)
        dim_level = brightness / 255.0
        transition = kwargs.get(ATTR_TRANSITION, 0.5)

        await self._device.set_rgb_dim_level_with_time(
            channelIndex=self._channel,
            rgb=simple_rgb_color,
            dimLevel=dim_level,
            onTime=0,
            rampTime=transition,
        )

    async def async_turn_off(self, **kwargs: Any) -> None:
        """Turn the light off."""
        simple_rgb_color = self._func_channel.simpleRGBColorState
        transition = kwargs.get(ATTR_TRANSITION, 0.5)

        await self._device.set_rgb_dim_level_with_time(
            channelIndex=self._channel,
            rgb=simple_rgb_color,
            dimLevel=0.0,
            onTime=0,
            rampTime=transition,
        )


def _convert_color(color: tuple) -> RGBColorState:
    """Convert the given color to the reduced RGBColorState color.

    RGBColorStat contains only 8 colors including white and black,
    so a conversion is required.
    """
    if color is None:
        return RGBColorState.WHITE

    hue = int(color[0])
    saturation = int(color[1])
    if saturation < 5:
        return RGBColorState.WHITE
    if 30 < hue <= 90:
        return RGBColorState.YELLOW
    if 90 < hue <= 160:
        return RGBColorState.GREEN
    if 150 < hue <= 210:
        return RGBColorState.TURQUOISE
    if 210 < hue <= 270:
        return RGBColorState.BLUE
    if 270 < hue <= 330:
        return RGBColorState.PURPLE
    return RGBColorState.RED
