from __future__ import annotations

import abc

from pypika.terms import Function
from pypika.utils import format_alias_sql


class _AbstractSearchString(Function, metaclass=abc.ABCMeta):
    def __init__(self, name, pattern: str, alias: str | None = None):
        super().__init__(self.clickhouse_function(), name, alias=alias)

        self._pattern = pattern

    @classmethod
    @abc.abstractmethod
    def clickhouse_function(cls) -> str:
        pass

    def get_sql(self, with_alias=False, with_namespace=False, quote_char=None, dialect=None, **kwargs):
        args = []
        for p in self.args:
            if hasattr(p, "get_sql"):
                args.append('toString("{arg}")'.format(arg=p.get_sql(with_alias=False, **kwargs)))
            else:
                args.append(str(p))

        sql = "{name}({args},'{pattern}')".format(
            name=self.name,
            args=",".join(args),
            pattern=self._pattern,
        )
        return format_alias_sql(sql, self.alias, **kwargs)


class Match(_AbstractSearchString):
    @classmethod
    def clickhouse_function(cls) -> str:
        return "match"


class Like(_AbstractSearchString):
    @classmethod
    def clickhouse_function(cls) -> str:
        return "like"


class NotLike(_AbstractSearchString):
    @classmethod
    def clickhouse_function(cls) -> str:
        return "notLike"


class _AbstractMultiSearchString(Function, metaclass=abc.ABCMeta):
    def __init__(self, name, patterns: list, alias: str | None = None):
        super().__init__(self.clickhouse_function(), name, alias=alias)

        self._patterns = patterns

    @classmethod
    @abc.abstractmethod
    def clickhouse_function(cls) -> str:
        pass

    def get_sql(self, with_alias=False, with_namespace=False, quote_char=None, dialect=None, **kwargs):
        args = []
        for p in self.args:
            if hasattr(p, "get_sql"):
                args.append('toString("{arg}")'.format(arg=p.get_sql(with_alias=False, **kwargs)))
            else:
                args.append(str(p))

        sql = "{name}({args},[{patterns}])".format(
            name=self.name,
            args=",".join(args),
            patterns=",".join(["'%s'" % i for i in self._patterns]),
        )
        return format_alias_sql(sql, self.alias, **kwargs)


class MultiSearchAny(_AbstractMultiSearchString):
    @classmethod
    def clickhouse_function(cls) -> str:
        return "multiSearchAny"


class MultiMatchAny(_AbstractMultiSearchString):
    @classmethod
    def clickhouse_function(cls) -> str:
        return "multiMatchAny"
