"""Provides device automations for homekit devices."""
from typing import List

from aiohomekit.model.characteristics import CharacteristicsTypes
from aiohomekit.model.characteristics.const import InputEventValues
from aiohomekit.model.services import ServicesTypes
from aiohomekit.utils import clamp_enum_to_char
import voluptuous as vol

from homeassistant.components.automation import AutomationActionType
from homeassistant.components.device_automation import TRIGGER_BASE_SCHEMA
from homeassistant.const import CONF_DEVICE_ID, CONF_DOMAIN, CONF_PLATFORM, CONF_TYPE
from homeassistant.core import CALLBACK_TYPE, HomeAssistant, callback
from homeassistant.helpers.typing import ConfigType

from .const import DOMAIN, KNOWN_DEVICES, TRIGGERS

TRIGGER_TYPES = {
    "button1",
    "button2",
    "button3",
    "button4",
    "button5",
    "button6",
    "button7",
    "button8",
    "button9",
    "button10",
}
TRIGGER_SUBTYPES = {"single_press", "double_press", "long_press"}

CONF_IID = "iid"
CONF_SUBTYPE = "subtype"

TRIGGER_SCHEMA = TRIGGER_BASE_SCHEMA.extend(
    {
        vol.Required(CONF_TYPE): vol.In(TRIGGER_TYPES),
        vol.Required(CONF_SUBTYPE): vol.In(TRIGGER_SUBTYPES),
    }
)

HK_TO_HA_INPUT_EVENT_VALUES = {
    InputEventValues.SINGLE_PRESS: "single_press",
    InputEventValues.DOUBLE_PRESS: "double_press",
    InputEventValues.LONG_PRESS: "long_press",
}


class TriggerSource:
    """Represents a stateless source of event data from HomeKit."""

    def __init__(self, connection, aid, triggers):
        """Initialize a set of triggers for a device."""
        self._hass = connection.hass
        self._connection = connection
        self._aid = aid
        self._triggers = {}
        for trigger in triggers:
            self._triggers[(trigger["type"], trigger["subtype"])] = trigger
        self._callbacks = {}

    def fire(self, iid, value):
        """Process events that have been received from a HomeKit accessory."""
        for event_handler in self._callbacks.get(iid, []):
            event_handler(value)

    def async_get_triggers(self):
        """List device triggers for homekit devices."""
        yield from self._triggers

    async def async_attach_trigger(
        self,
        config: TRIGGER_SCHEMA,
        action: AutomationActionType,
        automation_info: dict,
    ) -> CALLBACK_TYPE:
        """Attach a trigger."""

        def event_handler(char):
            if config[CONF_SUBTYPE] != HK_TO_HA_INPUT_EVENT_VALUES[char["value"]]:
                return
            self._hass.async_create_task(action({"trigger": config}))

        trigger = self._triggers[config[CONF_TYPE], config[CONF_SUBTYPE]]
        iid = trigger["characteristic"]

        self._connection.add_watchable_characteristics([(self._aid, iid)])
        self._callbacks.setdefault(iid, []).append(event_handler)

        def async_remove_handler():
            if iid in self._callbacks:
                self._callbacks[iid].remove(event_handler)

        return async_remove_handler


def enumerate_stateless_switch(service):
    """Enumerate a stateless switch, like a single button."""

    # A stateless switch that has a SERVICE_LABEL_INDEX is part of a group
    # And is handled separately
    if service.has(CharacteristicsTypes.SERVICE_LABEL_INDEX):
        if len(service.linked) > 0:
            return []

    char = service[CharacteristicsTypes.INPUT_EVENT]

    # HomeKit itself supports single, double and long presses. But the
    # manufacturer might not - clamp options to what they say.
    all_values = clamp_enum_to_char(InputEventValues, char)

    results = []
    for event_type in all_values:
        results.append(
            {
                "characteristic": char.iid,
                "value": event_type,
                "type": "button1",
                "subtype": HK_TO_HA_INPUT_EVENT_VALUES[event_type],
            }
        )
    return results


def enumerate_stateless_switch_group(service):
    """Enumerate a group of stateless switches, like a remote control."""
    switches = list(
        service.accessory.services.filter(
            service_type=ServicesTypes.STATELESS_PROGRAMMABLE_SWITCH,
            child_service=service,
            order_by=[CharacteristicsTypes.SERVICE_LABEL_INDEX],
        )
    )

    results = []
    for idx, switch in enumerate(switches):
        char = switch[CharacteristicsTypes.INPUT_EVENT]

        # HomeKit itself supports single, double and long presses. But the
        # manufacturer might not - clamp options to what they say.
        all_values = clamp_enum_to_char(InputEventValues, char)

        for event_type in all_values:
            results.append(
                {
                    "characteristic": char.iid,
                    "value": event_type,
                    "type": f"button{idx + 1}",
                    "subtype": HK_TO_HA_INPUT_EVENT_VALUES[event_type],
                }
            )
    return results


def enumerate_doorbell(service):
    """Enumerate doorbell buttons."""
    input_event = service[CharacteristicsTypes.INPUT_EVENT]

    # HomeKit itself supports single, double and long presses. But the
    # manufacturer might not - clamp options to what they say.
    all_values = clamp_enum_to_char(InputEventValues, input_event)

    results = []
    for event_type in all_values:
        results.append(
            {
                "characteristic": input_event.iid,