from abc import abstractmethod
from typing import Any, Awaitable, Callable, Dict, Optional

from .base import Base
from .request import Request
from .response import Response


class BackendConfig:
    """Base class for backend config."""
    pass


class BackendOptions:
    """Base class for backend options."""
    pass


class Backend(Base):
    """Main class used by the backend subclasses. Inherits Base."""
    @abstractmethod
    async def start(self) -> None:
        """Abstract method to start the backend.

        Must be implemented in the subclass
        """
        pass

    @abstractmethod
    async def stop(self) -> None:
        """Abstract method to stop the backend.

        Must be implemented in the subclass

        """
        pass

    @abstractmethod
    def is_running(self) -> bool:
        """Abstract method to check if the backend is running.

        Must be implemented in the subclass

        """
        pass

    @abstractmethod
    async def attach(self,
                     task_name: str,
                     options: Dict[str, Any],
                     callback: Callable[[Any], Awaitable[None]]) -> None:
        """Abstract method to attach to the backend.

        Must be implemented in the subclass

        """
        pass

    @abstractmethod
    def config(self) -> BackendConfig:
        """Abstract method to fetch the backend's config.

        Must be implemented in the subclass

        """
        pass

    @abstractmethod
    async def detach(self, task_name: str) -> None:
        """Abstract method to detach from the backend.

        Must be implemented in the subclass

        """

    @abstractmethod
    async def send_response(self,
                            request: Request,
                            response: Response) -> None:
        """Abstract method to send the response message.

        Must be implemented in the subclass

        """
        pass

    @abstractmethod
    async def send_request(self, request: Request) -> None:
        """Abstract method to send a new request.

        Must be implemented in the subclass

        """
        pass
