"""Fully Kiosk Browser switch."""

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

from fullykiosk import FullyKiosk

from homeassistant.components.switch import SwitchEntity, SwitchEntityDescription
from homeassistant.const import EntityCategory
from homeassistant.core import CALLBACK_TYPE, HomeAssistant, callback
from homeassistant.helpers.entity_platform import AddConfigEntryEntitiesCallback

from . import FullyKioskConfigEntry
from .coordinator import FullyKioskDataUpdateCoordinator
from .entity import FullyKioskEntity


@dataclass(frozen=True, kw_only=True)
class FullySwitchEntityDescription(SwitchEntityDescription):
    """Fully Kiosk Browser switch entity description."""

    on_action: Callable[[FullyKiosk], Any]
    off_action: Callable[[FullyKiosk], Any]
    is_on_fn: Callable[[dict[str, Any]], Any]
    mqtt_on_event: str | None
    mqtt_off_event: str | None


SWITCHES: tuple[FullySwitchEntityDescription, ...] = (
    FullySwitchEntityDescription(
        key="screensaver",
        translation_key="screensaver",
        on_action=lambda fully: fully.startScreensaver(),
        off_action=lambda fully: fully.stopScreensaver(),
        is_on_fn=lambda data: data.get("isInScreensaver"),
        mqtt_on_event="onScreensaverStart",
        mqtt_off_event="onScreensaverStop",
    ),
    FullySwitchEntityDescription(
        key="maintenance",
        translation_key="maintenance",
        entity_category=EntityCategory.CONFIG,
        on_action=lambda fully: fully.enableLockedMode(),
        off_action=lambda fully: fully.disableLockedMode(),
        is_on_fn=lambda data: data.get("maintenanceMode"),
        mqtt_on_event=None,
        mqtt_off_event=None,
    ),
    FullySwitchEntityDescription(
        key="kiosk",
        translation_key="kiosk",
        entity_category=EntityCategory.CONFIG,
        on_action=lambda fully: fully.lockKiosk(),
        off_action=lambda fully: fully.unlockKiosk(),
        is_on_fn=lambda data: data.get("kioskLocked"),
        mqtt_on_event=None,
        mqtt_off_event=None,
    ),
    FullySwitchEntityDescription(
        key="motion-detection",
        translation_key="motion_detection",
        entity_category=EntityCategory.CONFIG,
        on_action=lambda fully: fully.enableMotionDetection(),
        off_action=lambda fully: fully.disableMotionDetection(),
        is_on_fn=lambda data: data["settings"].get("motionDetection"),
        mqtt_on_event=None,
        mqtt_off_event=None,
    ),
    FullySwitchEntityDescription(
        key="screenOn",
        translation_key="screen_on",
        on_action=lambda fully: fully.screenOn(),
        off_action=lambda fully: fully.screenOff(),
        is_on_fn=lambda data: data.get("screenOn"),
        mqtt_on_event="screenOn",
        mqtt_off_event="screenOff",
    ),
)


async def async_setup_entry(
    hass: HomeAssistant,
    config_entry: FullyKioskConfigEntry,
    async_add_entities: AddConfigEntryEntitiesCallback,
) -> None:
    """Set up the Fully Kiosk Browser switch."""
    coordinator = config_entry.runtime_data

    async_add_entities(
        FullySwitchEntity(coordinator, description) for description in SWITCHES
    )


class FullySwitchEntity(FullyKioskEntity, SwitchEntity):
    """Fully Kiosk Browser switch entity."""

    entity_description: FullySwitchEntityDescription

    def __init__(
        self,
        coordinator: FullyKioskDataUpdateCoordinator,
        description: FullySwitchEntityDescription,
    ) -> None:
        """Initialize the Fully Kiosk Browser switch entity."""
        super().__init__(coordinator)
        self.entity_description = description
        self._attr_unique_id = f"{coordinator.data['deviceID']}-{description.key}"
        self._turned_on_subscription: CALLBACK_TYPE | None = None
        self._turned_off_subscription: CALLBACK_TYPE | None = None

    @override
    async def async_added_to_hass(self) -> None:
        """When entity is added to hass."""
        await super().async_added_to_hass()
        description = self.entity_description
        self._turned_on_subscription = await self.mqtt_subscribe(
            description.mqtt_off_event, self._turn_off
        )
        self._turned_off_subscription = await self.mqtt_subscribe(
            description.mqtt_on_event, self._turn_on
        )

    @override
    async def async_will_remove_from_hass(self) -> None:
        """Close MQTT subscriptions when removed."""
        await super().async_will_remove_from_hass()
        if self._turned_off_subscription is not None:
            self._turned_off_subscription()
        if self._turned_on_subscription is not None:
            self._turned_on_subscription()

    @override
    async def async_turn_on(self, **kwargs: Any) -> None:
        """Turn the entity on."""
        await self.entity_description.on_action(self.coordinator.fully)
        await self.coordinator.async_refresh()

    @override
    async def async_turn_off(self, **kwargs: Any) -> None:
        """Turn the entity off."""
        await self.entity_description.off_action(self.coordinator.fully)
        await self.coordinator.async_refresh()

    def _turn_off(self, **kwargs: Any) -> None:
        """Optimistically turn off."""
        self._attr_is_on = False
        self.async_write_ha_state()

    def _turn_on(self, **kwargs: Any) -> None:
        """Optimistically turn on."""
        self._attr_is_on = True
        self.async_write_ha_state()

    @callback
    @override
    def _handle_coordinator_update(self) -> None:
        """Handle updated data from the coordinator."""
        self._attr_is_on = bool(self.entity_description.is_on_fn(self.coordinator.data))
        self.async_write_ha_state()
