"""Implementation of the dimmer config module found in dimmers."""

from __future__ import annotations

import logging
from datetime import timedelta
from typing import Any, Final, cast

from ...exceptions import KasaException
from ...feature import Feature
from ..iotmodule import IotModule, merge

_LOGGER = logging.getLogger(__name__)


def _td_to_ms(td: timedelta) -> int:
    """
    Convert timedelta to integer milliseconds.

    Uses default float to integer rounding.
    """
    return int(td / timedelta(milliseconds=1))


class Dimmer(IotModule):
    """Implements the dimmer config module."""

    THRESHOLD_ABS_MIN: Final[int] = 0
    # Strange value, but verified against hardware (KS220).
    THRESHOLD_ABS_MAX: Final[int] = 51
    FADE_TIME_ABS_MIN: Final[timedelta] = timedelta(seconds=0)
    # Arbitrary, but set low intending GENTLE FADE for longer fades.
    FADE_TIME_ABS_MAX: Final[timedelta] = timedelta(seconds=10)
    GENTLE_TIME_ABS_MIN: Final[timedelta] = timedelta(seconds=0)
    # Arbitrary, but reasonable default.
    GENTLE_TIME_ABS_MAX: Final[timedelta] = timedelta(seconds=120)
    # Verified against KS220.
    RAMP_RATE_ABS_MIN: Final[int] = 10
    # Verified against KS220.
    RAMP_RATE_ABS_MAX: Final[int] = 50

    def _initialize_features(self) -> None:
        """Initialize features after the initial update."""
        self._add_feature(
            Feature(
                device=self._device,
                container=self,
                id="dimmer_threshold_min",
                name="Minimum dimming level",
                icon="mdi:lightbulb-on-20",
                attribute_getter="threshold_min",
                attribute_setter="set_threshold_min",
                range_getter=lambda: (self.THRESHOLD_ABS_MIN, self.THRESHOLD_ABS_MAX),
                type=Feature.Type.Number,
                category=Feature.Category.Config,
            )
        )

        self._add_feature(
            Feature(
                device=self._device,
                container=self,
                id="dimmer_fade_off_time",
                name="Dimmer fade off time",
                icon="mdi:clock-in",
                attribute_getter="fade_off_time",
                attribute_setter="set_fade_off_time",
                range_getter=lambda: (
                    _td_to_ms(self.FADE_TIME_ABS_MIN),
                    _td_to_ms(self.FADE_TIME_ABS_MAX),
                ),
                type=Feature.Type.Number,
                category=Feature.Category.Config,
            )
        )

        self._add_feature(
            Feature(
                device=self._device,
                container=self,
                id="dimmer_fade_on_time",
                name="Dimmer fade on time",
                icon="mdi:clock-out",
                attribute_getter="fade_on_time",
                attribute_setter="set_fade_on_time",
                range_getter=lambda: (
                    _td_to_ms(self.FADE_TIME_ABS_MIN),
                    _td_to_ms(self.FADE_TIME_ABS_MAX),
                ),
                type=Feature.Type.Number,
                category=Feature.Category.Config,
            )
        )

        self._add_feature(
            Feature(
                device=self._device,
                container=self,
                id="dimmer_gentle_off_time",
                name="Dimmer gentle off time",
                icon="mdi:clock-in",
                attribute_getter="gentle_off_time",
                attribute_setter="set_gentle_off_time",
                range_getter=lambda: (
                    _td_to_ms(self.GENTLE_TIME_ABS_MIN),
                    _td_to_ms(self.GENTLE_TIME_ABS_MAX),
                ),
                type=Feature.Type.Number,
                category=Feature.Category.Config,
            )
        )

        self._add_feature(
            Feature(
                device=self._device,
                container=self,
                id="dimmer_gentle_on_time",
                name="Dimmer gentle on time",
                icon="mdi:clock-out",
                attribute_getter="gentle_on_time",
                attribute_setter="set_gentle_on_time",
                range_getter=lambda: (
                    _td_to_ms(self.GENTLE_TIME_ABS_MIN),
                    _td_to_ms(self.GENTLE_TIME_ABS_MAX),
                ),
                type=Feature.Type.Number,
                category=Feature.Category.Config,
            )
        )

        self._add_feature(
            Feature(
                device=self._device,
                container=self,
                id="dimmer_ramp_rate",
                name="Dimmer ramp rate",
                icon="mdi:clock-fast",
                attribute_getter="ramp_rate",
                attribute_setter="set_ramp_rate",
                range_getter=lambda: (self.RAMP_RATE_ABS_MIN, self.RAMP_RATE_ABS_MAX),
                type=Feature.Type.Number,
                category=Feature.Category.Config,
            )
        )

    def query(self) -> dict:
        """Request Dimming configuration."""
        req = merge(
            self.query_for_command("get_dimmer_parameters"),
            self.query_for_command("get_default_behavior"),
        )

        return req

    @property
    def config(self) -> dict[str, Any]:
        """Return current configuration."""
        return self.data["get_dimmer_parameters"]

    @property
    def threshold_min(self) -> int:
        """Return the minimum dimming level for this dimmer."""
        return self.config["minThreshold"]

    async def set_threshold_min(self, min: int) -> dict:
        """Set the minimum dimming level for this dimmer.

        The value will depend on the luminaries connected to the dimmer.

        :param min: The minimum dimming level, in the range 0-51.
        """
        if min < self.THRESHOLD_ABS_MIN or min > self.THRESHOLD_ABS_MAX:
            raise KasaException(
                "Minimum dimming threshold is outside the supported range: "
                f"{self.THRESHOLD_ABS_MIN}-{self.THRESHOLD_ABS_MAX}"
            )
        return await self.call("calibrate_brightness", {"minThreshold": min})

    @property
    def fade_off_time(self) -> timedelta:
        """Return the fade off animation duration."""
        return timedelta(milliseconds=cast(int, self.config["fadeOffTime"]))

    async def set_fade_off_time(self, time: int | timedelta) -> dict:
        """Set the duration of the fade off animation.

        :param time: The animation duration, in ms.
        """
        if isinstance(time, int):
            time = timedelta(milliseconds=time)
        if time < self.FADE_TIME_ABS_MIN or time > self.FADE_TIME_ABS_MAX:
            raise KasaException(
                "Fade time is outside the bounds of the supported range:"
                f"{self.FADE_TIME_ABS_MIN}-{self.FADE_TIME_ABS_MAX}"
            )
        return await self.call("set_fade_off_time", {"fadeTime": _td_to_ms(time)})

    @property
    def fade_on_time(self) -> timedelta:
        """Return the fade on animation duration."""
        return timedelta(milliseconds=cast(int, self.config["fadeOnTime"]))

    async def set_fade_on_time(self, time: int | timedelta) -> dict:
        """Set the duration of the fade on animation.

        :param time: The animation duration, in ms.
        """
        if isinstance(time, int):
            time = timedelta(milliseconds=time)
        if time < self.FADE_TIME_ABS_MIN or time > self.FADE_TIME_ABS_MAX:
            raise KasaException(
                "Fade time is outside the bounds of the supported range:"
                f"{self.FADE_TIME_ABS_MIN}-{self.FADE_TIME_ABS_MAX}"
            )
        return await self.call("set_fade_on_time", {"fadeTime": _td_to_ms(time)})

    @property
    def gentle_off_time(self) -> timedelta:
        """Return the gentle fade off animation duration."""
        return timedelta(milliseconds=cast(int, self.config["gentleOffTime"]))

    async def set_gentle_off_time(self, time: int | timedelta) -> dict:
        """Set the duration of the gentle fade off animation.

        :param time: The animation duration, in ms.
        """
        if isinstance(time, int):
            time = timedelta(milliseconds=time)
        if time < self.GENTLE_TIME_ABS_MIN or time > self.GENTLE_TIME_ABS_MAX:
            raise KasaException(
                "Gentle off time is outside the bounds of the supported range: "
                f"{self.GENTLE_TIME_ABS_MIN}-{self.GENTLE_TIME_ABS_MAX}."
            )
        return await self.call("set_gentle_off_time", {"duration": _td_to_ms(time)})

    @property
    def gentle_on_time(self) -> timedelta:
        """Return the gentle fade on animation duration."""
        return timedelta(milliseconds=cast(int, self.config["gentleOnTime"]))

    async def set_gentle_on_time(self, time: int | timedelta) -> dict:
        """Set the duration of the gentle fade on animation.

        :param time: The animation duration, in ms.
        """
        if isinstance(time, int):
            time = timedelta(milliseconds=time)
        if time < self.GENTLE_TIME_ABS_MIN or time > self.GENTLE_TIME_ABS_MAX:
            raise KasaException(
                "Gentle off time is outside the bounds of the supported range: "
                f"{self.GENTLE_TIME_ABS_MIN}-{self.GENTLE_TIME_ABS_MAX}."
            )
        return await self.call("set_gentle_on_time", {"duration": _td_to_ms(time)})

    @property
    def ramp_rate(self) -> int:
        """Return the rate that the dimmer buttons increment the dimmer level."""
        return self.config["rampRate"]

    async def set_ramp_rate(self, rate: int) -> dict:
        """Set how quickly to ramp the dimming level when using the dimmer buttons.

        :param rate: The rate to increment the dimming level with each press.
        """
        if rate < self.RAMP_RATE_ABS_MIN or rate > self.RAMP_RATE_ABS_MAX:
            raise KasaException(
                "Gentle off time is outside the bounds of the supported range:"
                f"{self.RAMP_RATE_ABS_MIN}-{self.RAMP_RATE_ABS_MAX}"
            )
        return await self.call("set_button_ramp_rate", {"rampRate": rate})