from enum import Enum
from typing import Iterable
from uuid import UUID

from platypush.entities import Entity
from platypush.entities.bluetooth import BluetoothDevice
from platypush.entities.switches import EnumSwitch
from platypush.plugins.bluetooth.model import ServiceClass
from platypush.plugins.bluetooth._plugins import BaseBluetoothPlugin


def _make_uuid(prefix: str) -> UUID:
    """
    Utility method to create a Switchbot characteristic UUID given a hex
    prefix.
    """
    return UUID(f'cba20{prefix}-224d-11e6-9fb8-0002a5d5c51b')


class Command(Enum):
    """
    Supported commands.
    """

    PRESS = b'\x57\x01\x00'
    ON = b'\x57\x01\x01'
    OFF = b'\x57\x01\x02'


class Characteristic(Enum):
    """
    GATT characteristic UUIDs supported by Switchbot devices.
    """

    TX = _make_uuid('002')
    RX = _make_uuid('003')
    SRV = _make_uuid('d00')


# pylint: disable=too-few-public-methods
class SwitchbotPlugin(BaseBluetoothPlugin):
    """
    Implements support for Switchbot devices.
    """

    def supports_device(self, device: BluetoothDevice) -> bool:
        return any(
            srv.service_class == ServiceClass.SWITCHBOT for srv in device.services
        )

    def _extract_entities(self, device: BluetoothDevice) -> Iterable[Entity]:
        return [
            EnumSwitch(
                id=f'{device.address}::switchbot',
                name='Switchbot',
                values=[cmd.name.lower() for cmd in Command],
                is_write_only=True,
            )
        ]

    def set(self, device: BluetoothDevice, value: str, **_) -> None:
        value = value.upper()
        cmd = getattr(Command, value, None)
        if not (cmd):
            raise AssertionError(
                f'No such command: {value}. Available commands: {list(Command)}.'
            )
        self._manager.write(device.address, cmd.value, Characteristic.TX.value)
