"""Support for Tuya siren."""

from typing import Any, override

from tuya_device_handlers.definition.siren import (
    SirenDefinition,
    get_default_definition,
)
from tuya_sharing import CustomerDevice, Manager

from homeassistant.components.siren import (
    SirenEntity,
    SirenEntityDescription,
    SirenEntityFeature,
)
from homeassistant.const import EntityCategory
from homeassistant.core import HomeAssistant, callback
from homeassistant.helpers.dispatcher import async_dispatcher_connect
from homeassistant.helpers.entity_platform import AddConfigEntryEntitiesCallback

from .const import TUYA_DISCOVERY_NEW, DeviceCategory, DPCode
from .coordinator import TuyaConfigEntry
from .entity import TuyaEntity

SIRENS: dict[DeviceCategory, tuple[SirenEntityDescription, ...]] = {
    DeviceCategory.CO2BJ: (
        SirenEntityDescription(
            key=DPCode.ALARM_SWITCH,
            entity_category=EntityCategory.CONFIG,
            translation_key="siren",
        ),
    ),
    DeviceCategory.DGNBJ: (
        SirenEntityDescription(
            key=DPCode.ALARM_SWITCH,
            translation_key="siren",
        ),
    ),
    DeviceCategory.SGBJ: (
        SirenEntityDescription(
            key=DPCode.ALARM_SWITCH,
            name=None,
        ),
    ),
    DeviceCategory.SP: (
        SirenEntityDescription(
            key=DPCode.SIREN_SWITCH,
            translation_key="siren",
        ),
    ),
}

# Smart Camera - Low power consumption camera (duplicate of `sp`)
SIRENS[DeviceCategory.DGHSXJ] = SIRENS[DeviceCategory.SP]


async def async_setup_entry(
    hass: HomeAssistant,
    entry: TuyaConfigEntry,
    async_add_entities: AddConfigEntryEntitiesCallback,
) -> None:
    """Set up Tuya siren dynamically through Tuya discovery."""
    manager = entry.runtime_data.manager

    @callback
    def async_discover_device(device_ids: list[str]) -> None:
        """Discover and add a discovered Tuya siren."""
        entities: list[TuyaSirenEntity] = []
        for device_id in device_ids:
            device = manager.device_map[device_id]
            if descriptions := SIRENS.get(device.category):
                entities.extend(
                    TuyaSirenEntity(device, manager, description, definition)
                    for description in descriptions
                    if (definition := get_default_definition(device, description.key))
                )

        async_add_entities(entities)

    async_discover_device([*manager.device_map])

    entry.async_on_unload(
        async_dispatcher_connect(hass, TUYA_DISCOVERY_NEW, async_discover_device)
    )


class TuyaSirenEntity(TuyaEntity, SirenEntity):
    """Tuya Siren Entity."""

    _attr_supported_features = SirenEntityFeature.TURN_ON | SirenEntityFeature.TURN_OFF

    def __init__(
        self,
        device: CustomerDevice,
        device_manager: Manager,
        description: SirenEntityDescription,
        definition: SirenDefinition,
    ) -> None:
        """Init Tuya Siren."""
        super().__init__(device, device_manager, description)
        self._dpcode_wrapper = definition.siren_wrapper

    @property
    @override
    def is_on(self) -> bool | None:
        """Return true if siren is on."""
        return self._read_wrapper(self._dpcode_wrapper)

    @override
    async def _process_device_update(
        self,
        updated_status_properties: list[str],
        dp_timestamps: dict[str, int] | None,
    ) -> bool:
        """Called when Tuya device sends an update with updated properties.

        Returns True if the Home Assistant state should be written,
        or False if the state write should be skipped.
        """
        return not self._dpcode_wrapper.skip_update(
            self.device, updated_status_properties, dp_timestamps
        )

    @override
    async def async_turn_on(self, **kwargs: Any) -> None:
        """Turn the siren on."""
        await self._async_send_wrapper_updates(self._dpcode_wrapper, True)

    @override
    async def async_turn_off(self, **kwargs: Any) -> None:
        """Turn the siren off."""
        await self._async_send_wrapper_updates(self._dpcode_wrapper, False)
