"""Support for TRMNL time entities."""

from collections.abc import Callable, Coroutine
from dataclasses import dataclass
from datetime import time
from typing import Any, override

from trmnl.models import Device

from homeassistant.components.time import TimeEntity, TimeEntityDescription
from homeassistant.const import EntityCategory
from homeassistant.core import HomeAssistant
from homeassistant.helpers.entity_platform import AddConfigEntryEntitiesCallback

from . import TRMNLConfigEntry
from .coordinator import TRMNLCoordinator
from .entity import TRMNLEntity, exception_handler

PARALLEL_UPDATES = 0


def _minutes_to_time(minutes: int) -> time:
    """Convert minutes since midnight to a time object."""
    return time(hour=minutes // 60, minute=minutes % 60)


def _time_to_minutes(value: time) -> int:
    """Convert a time object to minutes since midnight."""
    return value.hour * 60 + value.minute


@dataclass(frozen=True, kw_only=True)
class TRMNLTimeEntityDescription(TimeEntityDescription):
    """Describes a TRMNL time entity."""

    value_fn: Callable[[Device], time]
    set_value_fn: Callable[[TRMNLCoordinator, int, time], Coroutine[Any, Any, None]]


TIME_DESCRIPTIONS: tuple[TRMNLTimeEntityDescription, ...] = (
    TRMNLTimeEntityDescription(
        key="sleep_start_time",
        translation_key="sleep_start_time",
        entity_category=EntityCategory.CONFIG,
        value_fn=lambda device: _minutes_to_time(device.sleep_start_time),
        set_value_fn=lambda coordinator, device_id, value: (
            coordinator.client.update_device(
                device_id, sleep_start_time=_time_to_minutes(value)
            )
        ),
    ),
    TRMNLTimeEntityDescription(
        key="sleep_end_time",
        translation_key="sleep_end_time",
        entity_category=EntityCategory.CONFIG,
        value_fn=lambda device: _minutes_to_time(device.sleep_end_time),
        set_value_fn=lambda coordinator, device_id, value: (
            coordinator.client.update_device(
                device_id, sleep_end_time=_time_to_minutes(value)
            )
        ),
    ),
)


async def async_setup_entry(
    hass: HomeAssistant,
    entry: TRMNLConfigEntry,
    async_add_entities: AddConfigEntryEntitiesCallback,
) -> None:
    """Set up TRMNL time entities based on a config entry."""
    coordinator = entry.runtime_data

    known_device_ids: set[int] = set()

    def _async_entity_listener() -> None:
        new_ids = set(coordinator.data) - known_device_ids
        if new_ids:
            async_add_entities(
                TRMNLTimeEntity(coordinator, device_id, description)
                for device_id in new_ids
                for description in TIME_DESCRIPTIONS
            )
            known_device_ids.update(new_ids)

    entry.async_on_unload(coordinator.async_add_listener(_async_entity_listener))
    _async_entity_listener()


class TRMNLTimeEntity(TRMNLEntity, TimeEntity):
    """Defines a TRMNL time entity."""

    entity_description: TRMNLTimeEntityDescription

    def __init__(
        self,
        coordinator: TRMNLCoordinator,
        device_id: int,
        description: TRMNLTimeEntityDescription,
    ) -> None:
        """Initialize TRMNL time entity."""
        super().__init__(coordinator, device_id)
        self.entity_description = description
        self._attr_unique_id = f"{device_id}_{description.key}"

    @property
    @override
    def native_value(self) -> time:
        """Return the current time value."""
        return self.entity_description.value_fn(self._device)

    @exception_handler
    @override
    async def async_set_value(self, value: time) -> None:
        """Set the time value."""
        await self.entity_description.set_value_fn(
            self.coordinator, self._device_id, value
        )
        await self.coordinator.async_request_refresh()
