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

import entity_read.sql.inter.other_func
from entity_read import sql
from entity_read.entity import Entity
from .expression import Expression

key_to_function_factory = {
    "len": entity_read.sql.inter.other_func.FunctionGetSubqueryLength,
    "exists": entity_read.sql.inter.other_func.FunctionExists,
    "not_exists": entity_read.sql.inter.other_func.FunctionNotExists,
    "to_str": entity_read.sql.inter.other_func.FunctionCastToStr,
    "sub": entity_read.sql.inter.other_func.FunctionSub,
    "div": entity_read.sql.inter.other_func.FunctionDiv,
    "json_extract_text": entity_read.sql.inter.json_func.FunctionJsonExtractText,
    "json_has_key": entity_read.sql.inter.json_func.FunctionJsonHasKey,
}


@dataclass(frozen=True, kw_only=True, repr=False)
class Function(Expression):
    key: str
    args: list[Expression]

    @property
    def keep_subquery(self) -> bool:
        return self._get_factory().keep_subquery

    def _get_factory(self) -> type[sql.atoms.Function]:
        if (function_factory := key_to_function_factory.get(self.key)) is None:
            raise KeyError(f"Not found function {self.key!r}")
        return function_factory

    def eval(self, entity_type: type[Entity], variables: dict[str, sql.atoms.Selectable]) -> sql.atoms.Function:
        function_factory = self._get_factory()
        # noinspection PyArgumentList
        return function_factory(args=[arg.eval(entity_type, variables) for arg in self.args])

    def shortcut(self) -> str:
        return f"func.{self.key}({','.join([arg.shortcut() for arg in self.args])})"
