from abc import ABC
from typing import Optional, Type

from core.typing import FilterOperator


class CollectionFilterABC[T](ABC):
    def __init__(
        self,
        obj: Optional[dict],
        op: Optional[FilterOperator] = None,
        source_value: Optional[T] = None,
    ):
        ABC.__init__(self)
        self._obj = obj
        self._op: Optional[FilterOperator] = op
        self._source_value: Optional[T] = source_value

        self._resolvers: {} = {}

    def add_field(self, field: str, filter_type: Type["CollectionFilterABC"]):
        if field not in self._obj:
            return

        operator, value = next(iter(self._obj[field].items()))
        self._resolvers[field] = filter_type({field: value}, operator, value)

    def filter(self, x: T) -> bool:
        collected = []
        for field, resolver in self._resolvers.items():
            collected.append(resolver.resolve(getattr(x, field)))

        return all(collected)

    def resolve(self, i_value: T) -> bool:
        match self._op:
            case "equal":
                return self._source_value == i_value
            case "notEqual":
                return self._source_value != i_value
            case "greater":
                return self._source_value > i_value
            case "greaterOrEqual":
                return self._source_value >= i_value
            case "less":
                return self._source_value < i_value
            case "lessOrEqual":
                return self._source_value <= i_value
            case "isNull":
                return self._source_value is None
            case "isNotNull":
                return self._source_value is not None
            case "contains":
                return self._source_value in i_value
            case "notContains":
                return self._source_value not in i_value
            case "startsWith":
                return i_value.startswith(self._source_value)
            case "endsWith":
                return i_value.endswith(self._source_value)
            case _:
                raise Exception("Invalid operation")
