"""Interact with a TPLink Light Effect.

>>> from kasa import Discover, Module, LightState
>>>
>>> dev = await Discover.discover_single(
>>>     "127.0.0.3",
>>>     username="user@example.com",
>>>     password="great_password"
>>> )
>>> await dev.update()
>>> print(dev.alias)
Living Room Bulb

Light effects are accessed via the LightPreset module. To list available presets

>>> light_effect = dev.modules[Module.LightEffect]
>>> light_effect.effect_list
['Off', 'Party', 'Relax']

To view the currently selected effect:

>>> light_effect.effect
Off

To activate a light effect:

>>> await light_effect.set_effect("Party")
>>> await dev.update()
>>> light_effect.effect
Party

If the device supports it you can set custom effects:

>>> if light_effect.has_custom_effects:
>>>     effect_list = { "brightness", 50 }
>>>     await light_effect.set_custom_effect(effect_list)
>>> light_effect.has_custom_effects  # The device in this examples does not support \
custom effects
False
"""

from __future__ import annotations

from abc import ABC, abstractmethod

from ..feature import Feature
from ..module import Module


class LightEffect(Module, ABC):
    """Interface to represent a light effect module."""

    LIGHT_EFFECTS_OFF = "Off"
    LIGHT_EFFECTS_UNNAMED_CUSTOM = "Custom"

    def _initialize_features(self) -> None:
        """Initialize features."""
        device = self._device
        self._add_feature(
            Feature(
                device,
                id="light_effect",
                name="Light effect",
                container=self,
                attribute_getter="effect",
                attribute_setter="set_effect",
                category=Feature.Category.Primary,
                type=Feature.Type.Choice,
                choices_getter="effect_list",
            )
        )

    @property
    @abstractmethod
    def has_custom_effects(self) -> bool:
        """Return True if the device supports setting custom effects."""

    @property
    @abstractmethod
    def effect(self) -> str:
        """Return effect name."""

    @property
    @abstractmethod
    def effect_list(self) -> list[str]:
        """Return built-in effects list.

        Example:
            ['Aurora', 'Bubbling Cauldron', ...]
        """

    @abstractmethod
    async def set_effect(
        self,
        effect: str,
        *,
        brightness: int | None = None,
        transition: int | None = None,
    ) -> dict:
        """Set an effect on the device.

        If brightness or transition is defined,
        its value will be used instead of the effect-specific default.

        See :meth:`effect_list` for available effects,
        or use :meth:`set_custom_effect` for custom effects.

        :param str effect: The effect to set
        :param int brightness: The wanted brightness
        :param int transition: The wanted transition time
        """

    @abstractmethod
    async def set_custom_effect(
        self,
        effect_dict: dict,
    ) -> dict:
        """Set a custom effect on the device.

        :param str effect_dict: The custom effect dict to set
        """
