"""Lights on Zigbee Home Automation networks."""

from __future__ import annotations

from collections.abc import Mapping
import functools
import logging
from typing import Any

from zha.application.platforms.light.const import (
    ColorMode as ZhaColorMode,
    LightEntityFeature as ZhaLightEntityFeature,
)

from homeassistant.components.light import (
    ATTR_BRIGHTNESS,
    ATTR_COLOR_MODE,
    ATTR_COLOR_TEMP_KELVIN,
    ATTR_EFFECT,
    ATTR_FLASH,
    ATTR_TRANSITION,
    ATTR_XY_COLOR,
    ColorMode,
    LightEntity,
    LightEntityFeature,
)
from homeassistant.config_entries import ConfigEntry
from homeassistant.const import STATE_ON, Platform
from homeassistant.core import HomeAssistant, State, callback
from homeassistant.helpers.dispatcher import async_dispatcher_connect
from homeassistant.helpers.entity_platform import AddConfigEntryEntitiesCallback
from homeassistant.util import color as color_util

from .entity import ZHAEntity
from .helpers import (
    SIGNAL_ADD_ENTITIES,
    EntityData,
    async_add_entities as zha_async_add_entities,
    convert_zha_error_to_ha_error,
    get_zha_data,
)

ZHA_TO_HA_COLOR_MODE = {
    ZhaColorMode.UNKNOWN: ColorMode.UNKNOWN,
    ZhaColorMode.ONOFF: ColorMode.ONOFF,
    ZhaColorMode.BRIGHTNESS: ColorMode.BRIGHTNESS,
    ZhaColorMode.COLOR_TEMP: ColorMode.COLOR_TEMP,
    ZhaColorMode.XY: ColorMode.XY,
}

HA_TO_ZHA_COLOR_MODE = {v: k for k, v in ZHA_TO_HA_COLOR_MODE.items()}

OFF_BRIGHTNESS = "off_brightness"
OFF_WITH_TRANSITION = "off_with_transition"

_LOGGER = logging.getLogger(__name__)


async def async_setup_entry(
    hass: HomeAssistant,
    config_entry: ConfigEntry,
    async_add_entities: AddConfigEntryEntitiesCallback,
) -> None:
    """Set up the Zigbee Home Automation light from config entry."""
    zha_data = get_zha_data(hass)
    entities_to_create = zha_data.platforms[Platform.LIGHT]

    unsub = async_dispatcher_connect(
        hass,
        SIGNAL_ADD_ENTITIES,
        functools.partial(
            zha_async_add_entities, async_add_entities, Light, entities_to_create
        ),
    )
    config_entry.async_on_unload(unsub)


class Light(LightEntity, ZHAEntity):
    """Representation of a ZHA or ZLL light."""

    def __init__(self, entity_data: EntityData) -> None:
        """Initialize the ZHA light."""
        super().__init__(entity_data)
        color_modes: set[ColorMode] = set()
        has_brightness = False
        for color_mode in self.entity_data.entity.supported_color_modes:
            if color_mode == ZhaColorMode.BRIGHTNESS:
                has_brightness = True
            if color_mode not in (ZhaColorMode.BRIGHTNESS, ZhaColorMode.ONOFF):
                color_modes.add(ZHA_TO_HA_COLOR_MODE[color_mode])
        if color_modes:
            self._attr_supported_color_modes = color_modes
        elif has_brightness:
            color_modes.add(ColorMode.BRIGHTNESS)
            self._attr_supported_color_modes = color_modes
        else:
            color_modes.add(ColorMode.ONOFF)
            self._attr_supported_color_modes = color_modes

        features = LightEntityFeature(0)
        zha_features: ZhaLightEntityFeature = self.entity_data.entity.supported_features

        if ZhaLightEntityFeature.EFFECT in zha_features:
            features |= LightEntityFeature.EFFECT
        if ZhaLightEntityFeature.FLASH in zha_features:
            features |= LightEntityFeature.FLASH
        if ZhaLightEntityFeature.TRANSITION in zha_features:
            features |= LightEntityFeature.TRANSITION

        self._attr_supported_features = features

    @property
    def extra_state_attributes(self) -> Mapping[str, Any] | None:
        """Return entity specific state attributes."""
        state = self.entity_data.entity.state
        return {
            "off_with_transition": state.get("off_with_transition"),
            "off_brightness": state.get("off_brightness"),
        }

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

    @property
    def brightness(self) -> int:
        """Return the brightness of this light."""
        return self.entity_data.entity.brightness

    @property
    def max_color_temp_kelvin(self) -> int:
        """Return the coldest color_temp_kelvin that this light supports."""
        return color_util.color_temperature_mired_to_kelvin(
            self.entity_data.entity.min_mireds
        )

    @property
    def min_color_temp_kelvin(self) -> int:
        """Return the warmest color_temp_kelvin that this light supports."""
        return color_util.color_temperature_mired_to_kelvin(
            self.entity_data.entity.max_mireds
        )

    @property
    def xy_color(self) -> tuple[float, float] | None:
        """Return the xy color value [float, float]."""
        return self.entity_data.entity.xy_color

    @property
    def color_temp_kelvin(self) -> int | None:
        """Return the color temperature value in Kelvin."""
        return (
            color_util.color_temperature_mired_to_kelvin(mireds)
            if (mireds := self.entity_data.entity.color_temp)
            else None
        )

    @property
    def color_mode(self) -> ColorMode | None:
        """Return the color mode."""
        if self.entity_data.entity.color_mode is None:
            return None
        return ZHA_TO_HA_COLOR_MODE[self.entity_data.entity.color_mode]

    @property
    def effect_list(self) -> list[str] | None:
        """Return the list of supported effects."""
        return self.entity_data.entity.effect_list

    @property
    def effect(self) -> str | None:
        """Return the current effect."""
        return self.entity_data.entity.effect

    @convert_zha_error_to_ha_error
    async def async_turn_on(self, **kwargs: Any) -> None:
        """Turn the entity on."""
        color_temp = (
            color_util.color_temperature_kelvin_to_mired(color_temp_k)
            if (color_temp_k := kwargs.get(ATTR_COLOR_TEMP_KELVIN))
            else None
        )
        await self.entity_data.entity.async_turn_on(
            transition=kwargs.get(ATTR_TRANSITION),
            brightness=kwargs.get(ATTR_BRIGHTNESS),
            effect=kwargs.get(ATTR_EFFECT),
            flash=kwargs.get(ATTR_FLASH),
            color_temp=color_temp,
            xy_color=kwargs.get(ATTR_XY_COLOR),
        )
        self.async_write_ha_state()

    @convert_zha_error_to_ha_error
    async def async_turn_off(self, **kwargs: Any) -> None:
        """Turn the entity off."""
        await self.entity_data.entity.async_turn_off(
            transition=kwargs.get(ATTR_TRANSITION)
        )
        self.async_write_ha_state()

    @callback
    def restore_external_state_attributes(self, state: State) -> None:
        """Restore entity state."""
        color_temp = (
            color_util.color_temperature_kelvin_to_mired(color_temp_k)
            if (color_temp_k := state.attributes.get(ATTR_COLOR_TEMP_KELVIN))
            else None
        )
        self.entity_data.entity.restore_external_state_attributes(
            state=(state.state == STATE_ON),
            off_with_transition=state.attributes.get(OFF_WITH_TRANSITION),
            off_brightness=state.attributes.get(OFF_BRIGHTNESS),
            brightness=state.attributes.get(ATTR_BRIGHTNESS),
            color_temp=color_temp,
            xy_color=state.attributes.get(ATTR_XY_COLOR),
            color_mode=(
                HA_TO_ZHA_COLOR_MODE[ColorMode(state.attributes[ATTR_COLOR_MODE])]
                if state.attributes.get(ATTR_COLOR_MODE) is not None
                else None
            ),
            effect=state.attributes.get(ATTR_EFFECT),
        )