#  Copyright (C) 2023
#  ABM, Moscow
#
#  UNPUBLISHED PROPRIETARY MATERIAL.
#  ALL RIGHTS RESERVED.
#
#  Authors: Mike Orlov <m.orlov@abm-jsc.ru>
import abc
import typing
from dataclasses import dataclass

from entity_read import sql
from entity_read.entity import Entity
from entity_read.sql.atoms import Selectable
from .query_token import QueryToken


@dataclass(frozen=True, kw_only=True, repr=False)
class Expression(QueryToken, abc.ABC):

    @abc.abstractmethod
    def eval(self, entity_type: type[Entity], variables: dict[str, Selectable]) -> sql.atoms.Selectable:
        pass


def as_(self, key: str):
    from .alias import Alias
    return Alias(body=self, key=key)


setattr(Expression, 'as', as_)


def make_condition_generator(condition_key: str) -> typing.Callable[[Expression, typing.Any], Expression]:
    def condition_generator(self: Expression, *args: typing.Any):
        from .condition import Condition
        from .literal import Literal
        right_args = [a if isinstance(a, Expression) else Literal(body=a) for a in args]
        return Condition(
            args=[self] + right_args,
            key=condition_key,
        )
    return condition_generator


def make_and_set_condition_method(target: type[Expression], condition_key: str) -> None:
    setattr(target, condition_key, make_condition_generator(condition_key))


for key in ['eq', 'ne', 'gt', 'lt', 'ge', 'le', 'in', 'is_null', 'is_not_null', 'ilike', 'like']:
    make_and_set_condition_method(Expression, key)
