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

from entity_read.sql.atoms import Selectable, Aggregation


@dataclass(kw_only=True, frozen=True, slots=True)
class AggregationArray(Aggregation):
    type_: str = field(default=str, init=False)
    args: tuple[Selectable[Any]]
    filters: tuple[Selectable[Any], ...] = tuple()
    code: ClassVar[str] = 'array'

    def _to_sql(self, args_sql: list[str], filters_sql: str) -> str:
        return f"coalesce(jsonb_agg({args_sql[0]}){filters_sql}, '[]'::jsonb)"


@dataclass(kw_only=True, frozen=True, slots=True)
class AggregationUnique(Aggregation):
    type_: str = field(default=str, init=False)
    args: tuple[Selectable[Any]]
    filters: tuple[Selectable[Any], ...] = tuple()
    code: ClassVar[str] = 'unique'

    def _to_sql(self, args_sql: list[str], filters_sql: str) -> str:
        return f"coalesce(jsonb_agg(DISTINCT {args_sql[0]}){filters_sql}, '[]'::jsonb)"


@dataclass(kw_only=True, frozen=True, slots=True)
class AggregationCount(Aggregation):
    type_: str = field(default=str, init=False)
    args: tuple[Selectable[Any]]
    filters: tuple[Selectable[Any], ...] = tuple()
    code: ClassVar[str] = 'count'

    def _to_sql(self, args_sql: list[str], filters_sql: str) -> str:
        return f"count({args_sql[0] if args_sql else '*'}){filters_sql}"


@dataclass(kw_only=True, frozen=True, slots=True)
class AggregationSum(Aggregation):
    type_: str = field(default=str, init=False)
    args: tuple[Selectable[Any]]
    filters: tuple[Selectable[Any], ...] = tuple()
    code: ClassVar[str] = 'sum'

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


@dataclass(kw_only=True, frozen=True, slots=True)
class AggregationMax(Aggregation):
    type_: str = field(default=str, init=False)
    args: tuple[Selectable[Any]]
    filters: tuple[Selectable[Any], ...] = tuple()
    code: ClassVar[str] = 'max'

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


@dataclass(kw_only=True, frozen=True, slots=True)
class AggregationMin(Aggregation):
    type_: str = field(default=str, init=False)
    args: tuple[Selectable[Any]]
    filters: tuple[Selectable[Any], ...] = tuple()
    code: ClassVar[str] = 'min'

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