from uuid import UUID
from enum import Enum

from typing import Callable
from typing import Union
from typing import Optional

from abc import ABC
from abc import abstractmethod

from ..schema.base_schema import BlobValue
from ..schema.base_schema import Device
from ..schema.base_schema import Network
from ..schema.base_schema import NumberValue
from ..schema.base_schema import State
from ..schema.base_schema import StringValue
from ..schema.base_schema import XmlValue
from ..schema.base_schema import WappstoMethods


class StatusID(str, Enum):
    IDLE = "idle"
    # BATCHING = "batching"
    SENDING = "sending"
    SENDERROR = "send Error"
    SEND = "send"
    ERROR = "Error Reply"


class ServiceClass(ABC):

    # #########################################################################
    #                               Network API
    # #########################################################################

    @abstractmethod
    def subscribe_network_event(
        self,
        uuid: UUID,
        callback: Callable[[Network, WappstoMethods], None]
    ):
        pass

    @abstractmethod
    def post_network(self, data) -> bool:
        # url=f"/services/2.0/network/{uuid}",
        pass

    @abstractmethod
    def put_network(self, uuid: UUID, data) -> bool:
        pass

    @abstractmethod
    def get_network(self, uuid: UUID) -> Union[Network, None]:
        pass

    @abstractmethod
    def delete_network(self, uuid: UUID) -> bool:
        pass

    # #########################################################################
    #                                Device API
    # #########################################################################

    @abstractmethod
    def subscribe_device_event(
        self,
        uuid: UUID,
        callback: Callable[[Device, WappstoMethods], None]
    ):
        pass

    @abstractmethod
    def post_device(self, network_uuid: UUID, data: Device) -> bool:
        # url=f"/services/2.0/{uuid}/device",
        pass

    @abstractmethod
    def put_device(self, uuid: UUID, data: Device) -> bool:
        pass

    @abstractmethod
    def get_device_where(self, network_uuid: UUID, **kwargs: str) -> Optional[UUID]:
        pass

    @abstractmethod
    def get_device(self, uuid: UUID) -> Union[Device, None]:
        pass

    @abstractmethod
    def delete_device(self, uuid: UUID) -> bool:
        pass

    # #########################################################################
    #                                 Value API
    # #########################################################################

    ValueUnion = Union[StringValue, NumberValue, BlobValue, XmlValue]

    @abstractmethod
    def subscribe_value_event(
        self,
        uuid: UUID,
        callback: Callable[[ValueUnion, WappstoMethods], None]
    ):
        pass

    @abstractmethod
    def post_value(self, device_uuid: UUID, data: ValueUnion) -> bool:
        # url=f"/services/2.0/{uuid}/value",
        pass

    @abstractmethod
    def put_value(self, uuid: UUID, data: ValueUnion) -> bool:
        pass

    @abstractmethod
    def get_value_where(self, device_uuid: UUID, **kwargs: str) -> Optional[UUID]:
        pass

    @abstractmethod
    def get_value(self, uuid: UUID) -> Union[ValueUnion, None]:
        pass

    @abstractmethod
    def delete_value(self, uuid: UUID) -> bool:
        pass

    # #########################################################################
    #                                State API
    # #########################################################################

    @abstractmethod
    def subscribe_state_event(
        self,
        uuid: UUID,
        callback: Callable[[State, WappstoMethods], None]
    ):
        pass

    @abstractmethod
    def post_state(self, value_uuid: UUID, data: State) -> bool:
        # url=f"/services/2.0/{uuid}/state",
        pass

    @abstractmethod
    def put_state(self, uuid: UUID, data: State) -> bool:
        pass

    @abstractmethod
    def get_state(self, uuid: UUID) -> Union[State, None]:
        pass

    @abstractmethod
    def delete_state(self, uuid: UUID) -> bool:
        pass
