"""Switch platform for motionEye."""
from __future__ import annotations

from types import MappingProxyType
from typing import Any

from motioneye_client.client import MotionEyeClient
from motioneye_client.const import (
    KEY_MOTION_DETECTION,
    KEY_MOVIES,
    KEY_NAME,
    KEY_STILL_IMAGES,
    KEY_TEXT_OVERLAY,
    KEY_UPLOAD_ENABLED,
    KEY_VIDEO_STREAMING,
)

from homeassistant.components.switch import SwitchEntity, SwitchEntityDescription
from homeassistant.config_entries import ConfigEntry
from homeassistant.core import HomeAssistant, callback
from homeassistant.helpers.entity import EntityCategory
from homeassistant.helpers.entity_platform import AddEntitiesCallback
from homeassistant.helpers.update_coordinator import DataUpdateCoordinator

from . import MotionEyeEntity, get_camera_from_cameras, listen_for_new_cameras
from .const import CONF_CLIENT, CONF_COORDINATOR, DOMAIN, TYPE_MOTIONEYE_SWITCH_BASE

MOTIONEYE_SWITCHES = [
    SwitchEntityDescription(
        key=KEY_MOTION_DETECTION,
        name="Motion Detection",
        entity_registry_enabled_default=True,
        entity_category=EntityCategory.CONFIG,
    ),
    SwitchEntityDescription(
        key=KEY_TEXT_OVERLAY,
        name="Text Overlay",
        entity_registry_enabled_default=False,
        entity_category=EntityCategory.CONFIG,
    ),
    SwitchEntityDescription(
        key=KEY_VIDEO_STREAMING,
        name="Video Streaming",
        entity_registry_enabled_default=False,
        entity_category=EntityCategory.CONFIG,
    ),
    SwitchEntityDescription(
        key=KEY_STILL_IMAGES,
        name="Still Images",
        entity_registry_enabled_default=True,
        entity_category=EntityCategory.CONFIG,
    ),
    SwitchEntityDescription(
        key=KEY_MOVIES,
        name="Movies",
        entity_registry_enabled_default=True,
        entity_category=EntityCategory.CONFIG,
    ),
    SwitchEntityDescription(
        key=KEY_UPLOAD_ENABLED,
        name="Upload Enabled",
        entity_registry_enabled_default=False,
        entity_category=EntityCategory.CONFIG,
    ),
]


async def async_setup_entry(
    hass: HomeAssistant, entry: ConfigEntry, async_add_entities: AddEntitiesCallback
) -> None:
    """Set up motionEye from a config entry."""
    entry_data = hass.data[DOMAIN][entry.entry_id]

    @callback
    def camera_add(camera: dict[str, Any]) -> None:
        """Add a new motionEye camera."""
        async_add_entities(
            [
                MotionEyeSwitch(
                    entry.entry_id,
                    camera,
                    entry_data[CONF_CLIENT],
                    entry_data[CONF_COORDINATOR],
                    entry.options,
                    entity_description,
                )
                for entity_description in MOTIONEYE_SWITCHES
            ]
        )

    listen_for_new_cameras(hass, entry, camera_add)


class MotionEyeSwitch(MotionEyeEntity, SwitchEntity):
    """MotionEyeSwitch switch class."""

    def __init__(
        self,
        config_entry_id: str,
        camera: dict[str, Any],
        client: MotionEyeClient,
        coordinator: DataUpdateCoordinator,
        options: MappingProxyType[str, str],
        entity_description: SwitchEntityDescription,
    ) -> None:
        """Initialize the switch."""
        super().__init__(
            config_entry_id,
            f"{TYPE_MOTIONEYE_SWITCH_BASE}_{entity_description.key}",
            camera,
            client,
            coordinator,
            options,
            entity_description,
        )

    @property
    def name(self) -> str:
        """Return the name of the switch."""
        camera_prepend = f"{self._camera[KEY_NAME]} " if self._camera else ""
        return f"{camera_prepend}{self.entity_description.name}"

    @property
    def is_on(self) -> bool:
        """Return true if the switch is on."""
        return bool(
            self._camera and self._camera.get(self.entity_description.key, False)
        )

    async def _async_send_set_camera(self, value: bool) -> None:
        """Set a switch value."""

        # Fetch the very latest camera config to reduce the risk of updating with a
        # stale configuration.
        camera = await self._client.async_get_camera(self._camera_id)
        if camera:
            camera[self.entity_description.key] = value
            await self._client.async_set_camera(self._camera_id, camera)

    async def async_turn_on(self, **kwargs: Any) -> None:
        """Turn on the switch."""
        await self._async_send_set_camera(True)

    async def async_turn_off(self, **kwargs: Any) -> None:
        """Turn off the switch."""
        await self._async_send_set_camera(False)

    @callback
    def _handle_coordinator_update(self) -> None:
        """Handle updated data from the coordinator."""
        self._camera = get_camera_from_cameras(self._camera_id, self.coordinator.data)
        super()._handle_coordinator_update()