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

from entity_read.sql.atoms import Function, Selectable

if TYPE_CHECKING:
    from ..lower import LowerSelector


@dataclass(kw_only=True, frozen=True, slots=True)
class FunctionGetSubqueryLength(Function):
    type_: str = field(default=int, init=False)
    args: tuple[Selectable[list]]
    code: ClassVar[str] = 'len'

    def _to_sql(self, args_sql: list[str]) -> str:
        return f'jsonb_array_length({args_sql[0]})'


@dataclass(kw_only=True, frozen=True, slots=True)
class FunctionExists(Function):
    type_: str = field(default=int, init=False)
    args: tuple['LowerSelector']
    code: ClassVar[str] = 'exists'
    keep_subquery: ClassVar[bool] = True

    def _to_sql(self, args_sql: list[str]) -> str:
        return f'EXISTS ({args_sql[0]})'


@dataclass(kw_only=True, frozen=True, slots=True)
class FunctionNotExists(Function):
    type_: str = field(default=int, init=False)
    args: tuple['LowerSelector']
    code: ClassVar[str] = 'not_exists'
    keep_subquery: ClassVar[bool] = True

    def _to_sql(self, args_sql: list[str]) -> str:
        return f'NOT EXISTS ({args_sql[0]})'


@dataclass(kw_only=True, frozen=True, slots=True)
class FunctionCastToStr(Function):
    type_: str = field(default=str, init=False)
    args: tuple[Selectable[Any]]
    code: ClassVar[str] = 'to_str'

    def _to_sql(self, args_sql: list) -> str:
        return f"{args_sql[0]}::TEXT"


@dataclass(kw_only=True, frozen=True, slots=True)
class FunctionSub(Function):
    type_: str = field(default=str, init=False)
    args: tuple[Selectable[Any]]
    code: ClassVar[str] = 'sub'

    def _to_sql(self, args_sql: list) -> str:
        return f"{args_sql[0]} - {args_sql[1]}"


@dataclass(kw_only=True, frozen=True, slots=True)
class FunctionDiv(Function):
    type_: str = field(default=str, init=False)
    args: tuple[Selectable[Any]]
    code: ClassVar[str] = 'div'

    def _to_sql(self, args_sql: list) -> str:
        return f"{args_sql[0]} / {args_sql[1]}"


@dataclass(kw_only=True, frozen=True, slots=True)
class FunctionCastToDate(Function):
    type_: str = field(default=str, init=False)
    args: tuple[Selectable[Any]]
    code: ClassVar[str] = "to_date"

    def _to_sql(self, args_sql: list) -> str:
        return f"TO_DATE({args_sql[0]}, {args_sql[1]})"
