"""Support for EZVIZ Switch sensors."""

from __future__ import annotations

from dataclasses import dataclass
from typing import Any

from pyezviz.constants import DeviceSwitchType, SupportExt
from pyezviz.exceptions import HTTPError, PyEzvizError

from homeassistant.components.switch import (
    SwitchDeviceClass,
    SwitchEntity,
    SwitchEntityDescription,
)
from homeassistant.config_entries import ConfigEntry
from homeassistant.core import HomeAssistant, callback
from homeassistant.exceptions import HomeAssistantError
from homeassistant.helpers.entity_platform import AddEntitiesCallback

from .const import DATA_COORDINATOR, DOMAIN
from .coordinator import EzvizDataUpdateCoordinator
from .entity import EzvizEntity


@dataclass(frozen=True, kw_only=True)
class EzvizSwitchEntityDescription(SwitchEntityDescription):
    """Describe a EZVIZ switch."""

    supported_ext: str | None


SWITCH_TYPES: dict[int, EzvizSwitchEntityDescription] = {
    3: EzvizSwitchEntityDescription(
        key="3",
        translation_key="status_light",
        device_class=SwitchDeviceClass.SWITCH,
        supported_ext=None,
    ),
    7: EzvizSwitchEntityDescription(
        key="7",
        translation_key="privacy",
        device_class=SwitchDeviceClass.SWITCH,
        supported_ext=str(SupportExt.SupportPtzPrivacy.value),
    ),
    10: EzvizSwitchEntityDescription(
        key="10",
        translation_key="infrared_light",
        device_class=SwitchDeviceClass.SWITCH,
        supported_ext=str(SupportExt.SupportCloseInfraredLight.value),
    ),
    21: EzvizSwitchEntityDescription(
        key="21",
        translation_key="sleep",
        device_class=SwitchDeviceClass.SWITCH,
        supported_ext=str(SupportExt.SupportSleep.value),
    ),
    22: EzvizSwitchEntityDescription(
        key="22",
        translation_key="audio",
        device_class=SwitchDeviceClass.SWITCH,
        supported_ext=str(SupportExt.SupportAudioOnoff.value),
    ),
    25: EzvizSwitchEntityDescription(
        key="25",
        translation_key="motion_tracking",
        device_class=SwitchDeviceClass.SWITCH,
        supported_ext=str(SupportExt.SupportIntelligentTrack.value),
    ),
    29: EzvizSwitchEntityDescription(
        key="29",
        translation_key="all_day_video_recording",
        device_class=SwitchDeviceClass.SWITCH,
        supported_ext=str(SupportExt.SupportFulldayRecord.value),
    ),
    32: EzvizSwitchEntityDescription(
        key="32",
        translation_key="auto_sleep",
        device_class=SwitchDeviceClass.SWITCH,
        supported_ext=str(SupportExt.SupportAutoSleep.value),
    ),
    301: EzvizSwitchEntityDescription(
        key="301",
        translation_key="flicker_light_on_movement",
        device_class=SwitchDeviceClass.SWITCH,
        supported_ext=str(SupportExt.SupportActiveDefense.value),
    ),
    305: EzvizSwitchEntityDescription(
        key="305",
        translation_key="pir_motion_activated_light",
        device_class=SwitchDeviceClass.SWITCH,
        supported_ext=str(SupportExt.SupportLightRelate.value),
    ),
    306: EzvizSwitchEntityDescription(
        key="306",
        translation_key="tamper_alarm",
        device_class=SwitchDeviceClass.SWITCH,
        supported_ext=str(SupportExt.SupportTamperAlarm.value),
    ),
    650: EzvizSwitchEntityDescription(
        key="650",
        translation_key="follow_movement",
        device_class=SwitchDeviceClass.SWITCH,
        supported_ext=str(SupportExt.SupportTracking.value),
    ),
}


async def async_setup_entry(
    hass: HomeAssistant, entry: ConfigEntry, async_add_entities: AddEntitiesCallback
) -> None:
    """Set up EZVIZ switch based on a config entry."""
    coordinator: EzvizDataUpdateCoordinator = hass.data[DOMAIN][entry.entry_id][
        DATA_COORDINATOR
    ]

    async_add_entities(
        EzvizSwitch(coordinator, camera, switch_number)
        for camera in coordinator.data
        for switch_number in coordinator.data[camera]["switches"]
        if switch_number in SWITCH_TYPES
        if SWITCH_TYPES[switch_number].supported_ext
        in coordinator.data[camera]["supportExt"]
        or SWITCH_TYPES[switch_number].supported_ext is None
    )


class EzvizSwitch(EzvizEntity, SwitchEntity):
    """Representation of a EZVIZ sensor."""

    def __init__(
        self, coordinator: EzvizDataUpdateCoordinator, serial: str, switch_number: int
    ) -> None:
        """Initialize the switch."""
        super().__init__(coordinator, serial)
        self._switch_number = switch_number
        self._attr_unique_id = (
            f"{serial}_{self._camera_name}.{DeviceSwitchType(switch_number).name}"
        )
        self.entity_description = SWITCH_TYPES[switch_number]
        self._attr_is_on = self.data["switches"][switch_number]

    async def async_turn_on(self, **kwargs: Any) -> None:
        """Change a device switch on the camera."""
        try:
            if await self.hass.async_add_executor_job(
                self.coordinator.ezviz_client.switch_status,
                self._serial,
                self._switch_number,
                1,
            ):
                self._attr_is_on = True
                self.async_write_ha_state()

        except (HTTPError, PyEzvizError) as err:
            raise HomeAssistantError(f"Failed to turn on switch {self.name}") from err

    async def async_turn_off(self, **kwargs: Any) -> None:
        """Change a device switch on the camera."""
        try:
            if await self.hass.async_add_executor_job(
                self.coordinator.ezviz_client.switch_status,
                self._serial,
                self._switch_number,
                0,
            ):
                self._attr_is_on = False
                self.async_write_ha_state()

        except (HTTPError, PyEzvizError) as err:
            raise HomeAssistantError(f"Failed to turn off switch {self.name}") from err

    @callback
    def _handle_coordinator_update(self) -> None:
        """Handle updated data from the coordinator."""
        self._attr_is_on = self.data["switches"].get(self._switch_number)
        super()._handle_coordinator_update()
