# Copyright (c) 2022 CloudZero - ALL RIGHTS RESERVED - PROPRIETARY AND CONFIDENTIAL
# Unauthorized copying of this file and/or project, via any medium is strictly prohibited.
# Direct all questions to legal@cloudzero.com
import abc
from enum import Enum
from typing import Mapping, List, Any, Type, Callable

from czc.api.v2.pagination import PaginationFiltering


class FilterType(Enum):
    def filter_value(self, item: Mapping) -> Any:
        return item.get(self.value)


class Filters(abc.ABC):
    @property
    @abc.abstractmethod
    def available(self) -> List[FilterType]:
        ...

    @property
    @abc.abstractmethod
    def current(self) -> Mapping[FilterType, List[Any]]:
        ...

    @property
    def _current_as_dict(self) -> dict:
        return {ft.value: v for ft, v in self.current.items()}

    @property
    def pagination_filtering(self) -> PaginationFiltering:
        def filter_by(f: FilterType) -> Callable[[Mapping, List[Any]], bool]:
            return lambda item, values: f.filter_value(item) in values

        return PaginationFiltering(
            filters=self._current_as_dict,
            filter_fns={f.value: filter_by(f) for f in self.current}
        )

    @property
    def filtering_info(self) -> dict:
        return dict(
            available=[ft.value for ft in self.available],
            current=self._current_as_dict
        )


class _EmptyFilters(Filters):
    @property
    def available(self) -> List[FilterType]:
        return []

    @property
    def current(self) -> Mapping[FilterType, List[Any]]:
        return {}


EMPTY_FILTERS = _EmptyFilters()


class _StandardFilters(Filters, abc.ABC):
    filters: Mapping[FilterType, List[Any]]

    def __init__(self, filters: Mapping[FilterType, List[Any]]):
        self.filters = filters

    @property
    def current(self) -> Mapping[FilterType, List[Any]]:
        return self.filters


def get_filter_class(filter_class: Type[FilterType]) -> Type[_StandardFilters]:
    class _Filters(_StandardFilters):
        @property
        def available(self) -> List[FilterType]:
            return list(filter_class)

    return _Filters
