from __future__ import annotations

import abc
from collections.abc import Callable

from . import utils
from .base import Operator
from .types import ListExpression


class LogicalOperator(Operator):
    def __init__(self, *ops: Operator):
        self.ops = list(ops)

    @abc.abstractmethod
    def expression(self) -> dict[str, ListExpression]:
        raise NotImplementedError


def _expression_factory(
    mongo_operator: str,
) -> Callable[[LogicalOperator], dict[str, ListExpression]]:
    def expression(self: LogicalOperator) -> dict[str, ListExpression]:
        expressions = [expr for op in self.ops if (expr := op.expression())]
        return {mongo_operator: expressions} if expressions else {}

    return expression


def create_logical_operator(name: str, mongo_operator: str) -> type[LogicalOperator]:
    return utils.create_operator(
        name=name, base=(LogicalOperator,), expression_factory=_expression_factory(mongo_operator)
    )


And = create_logical_operator(name="And", mongo_operator="$and")
Or = create_logical_operator(name="Or", mongo_operator="$or")
