from abc import ABC
from abc import abstractmethod
from typing import Iterable
from typing import List
from typing import Optional

from pyloot.types import ObjectDescriptor
from pyloot.types import ObjectTypeHistory


class BaseBackend(ABC):
    @abstractmethod
    def store(self, object_data: List[ObjectDescriptor]):
        """
        Store object data in the backend
        :param object_data: list of ::class::`ObjectDescriptor`
        """

    @abstractmethod
    def fetch(self, limit: Optional[int]) -> List[ObjectDescriptor]:
        """
        Get all object descriptors

        :param limit: limits number of results returned
        :return: list of ::class::`ObjectDescriptor`
        """

    @abstractmethod
    def fetch_by_id(self, _id: int) -> Optional[ObjectDescriptor]:
        """
        Get object descriptor by memory id

        :param _id: id of object as returned by `id()`
        :return: ::class::`ObjectDescriptor` if found otherwise `None`
        """

    @abstractmethod
    def fetch_children_of(self, _id: int) -> List[ObjectDescriptor]:
        """
        Get child object descriptors of an object given it's memory id

        :param _id: id of parent object as returned by `id()`
        :return: list of ::class::`ObjectDescriptor` if found otherwise an empty list is returned
        """

    @abstractmethod
    def fetch_parents_of(self, _id: int) -> List[ObjectDescriptor]:
        """
        Get child object descriptors of an object given it's memory id

        :param _id: id of parent object as returned by `id()`
        :return: list of ::class::`ObjectDescriptor` if found otherwise an empty list is returned
        """

    @abstractmethod
    def fetch_by_group(
        self, group: str, limit: Optional[int]
    ) -> List[ObjectDescriptor]:
        """
        Get object descriptors by its type name

        :param group: descriptor group
        :param limit: limits number of results returned
        :return: list of ::class::`ObjectDescriptor`
        """

    @abstractmethod
    def fetch_history(self, top: int = 100) -> List[ObjectTypeHistory]:
        """
        Get object history grouped by object_type

        :param top: limit history to the `top` number of entries based on cur count
        :return: list of ::class`ObjectTypeHistory`
        """

    @abstractmethod
    def get_ids(self) -> Iterable[int]:
        """
        Get object ids held by this class which should be ignored when
        collecting objects.

        :return: Iterable of int ids generated by `id()`
        """
