from operator import add as add
from operator import and_ as and_
from operator import contains as contains
from operator import eq as eq
from operator import ge as ge
from operator import getitem as getitem
from operator import gt as gt
from operator import inv as inv
from operator import le as le
from operator import lshift as lshift
from operator import lt as lt
from operator import mod as mod
from operator import mul as mul
from operator import ne as ne
from operator import neg as neg
from operator import or_ as or_
from operator import rshift as rshift
from operator import sub as sub
from operator import truediv as truediv
from typing import Any
from typing import Callable
from typing import Generic
from typing import NoReturn
from typing import Optional
from typing import overload
from typing import Type
from typing import TypeVar
from typing import Union

from . import sqltypes
from .elements import ClauseElement
from .elements import ColumnElement
from .type_api import TypeEngine

_F = TypeVar("_F", bound=Callable[..., Any])
_T = TypeVar("_T")
_TE = TypeVar("_TE", bound=TypeEngine[Any])
_OTE = TypeVar("_OTE", bound=TypeEngine[Any])
_CE = TypeVar("_CE", bound=ClauseElement)

div = truediv

class Operators(Generic[_CE]):
    def __and__(self, other: Any) -> _CE: ...
    def __or__(self, other: Any) -> _CE: ...
    def __invert__(self) -> _CE: ...
    def op(
        self,
        opstring: Any,
        precedence: int = ...,
        is_comparison: bool = ...,
        return_type: Optional[
            Union[Type[TypeEngine[Any]], TypeEngine[Any]]
        ] = ...,
    ) -> Callable[[Any], ClauseElement]: ...
    def bool_op(
        self, opstring: Any, precedence: int = ...
    ) -> Callable[[Any], _CE]: ...
    def operate(self, op: Any, *other: Any, **kwargs: Any) -> _CE: ...
    def reverse_operate(self, op: Any, other: Any, **kwargs: Any) -> _CE: ...

class custom_op:
    __name__: str = ...
    opstring: Any = ...
    precedence: int = ...
    is_comparison: bool = ...
    natural_self_precedent: bool = ...
    eager_grouping: bool = ...
    return_type: Optional[Union[Type[TypeEngine[Any]], TypeEngine[Any]]] = ...
    def __init__(
        self,
        opstring: Any,
        precedence: int = ...,
        is_comparison: bool = ...,
        return_type: Optional[
            Union[Type[TypeEngine[Any]], TypeEngine[Any]]
        ] = ...,
        natural_self_precedent: bool = ...,
        eager_grouping: bool = ...,
    ) -> None: ...
    def __eq__(self, other: Any) -> bool: ...
    def __hash__(self) -> int: ...
    def __call__(self, left: Any, right: Any, **kw: Any) -> ClauseElement: ...

class ColumnOperators(Operators[ColumnElement[_TE]], Generic[_TE]):
    # op requires custom override
    @overload
    def op(
        self,
        opstring: Any,
        precedence: int = ...,
        is_comparison: bool = ...,
    ) -> Callable[[Any], ColumnElement[_TE]]: ...
    @overload
    def op(
        self,
        opstring: Any,
        precedence: int = ...,
        is_comparison: bool = ...,
        return_type: Union[Type[_OTE], _OTE] = ...,
    ) -> Callable[[Any], ColumnElement[_OTE]]: ...
    timetuple: Any = ...
    # TODO https://github.com/sqlalchemy/sqlalchemy2-stubs/issues/114
    #  Can we also limit the "other" parameter? Most should be
    #  Same TypeEngine[_T] or _T, but in case of ORM expressions
    #  _T is a Mapped type, can we extract the pure python type from
    #  a TypeEngine bounded TypeVar?
    # def __lt__(
    #     self, other: Union[ColumnElement[TypeEngine[_T]], _T]
    # ) -> ColumnElement[sqltypes.Boolean]: ...
    def __lt__(self, other: Any) -> ColumnElement[sqltypes.Boolean]: ...
    def __le__(self, other: Any) -> ColumnElement[sqltypes.Boolean]: ...
    def __eq__(self, other: Any) -> ColumnElement[sqltypes.Boolean]: ...  # type: ignore[override]
    def __ne__(self, other: Any) -> ColumnElement[sqltypes.Boolean]: ...  # type: ignore[override]
    def is_distinct_from(
        self, other: Any
    ) -> ColumnElement[sqltypes.Boolean]: ...
    def is_not_distinct_from(
        self, other: Any
    ) -> ColumnElement[sqltypes.Boolean]: ...
    def __gt__(self, other: Any) -> ColumnElement[sqltypes.Boolean]: ...
    def __ge__(self, other: Any) -> ColumnElement[sqltypes.Boolean]: ...
    def __neg__(self) -> ColumnElement[_TE]: ...
    def __contains__(self, other: Any) -> ColumnElement[sqltypes.Boolean]: ...
    # TODO __getitem__ is hard: Arrays return Random Types and Strings return Strings?
    def __getitem__(self, index: Any) -> ColumnElement[Any]: ...
    def __lshift__(self, other: Any) -> ColumnElement[_TE]: ...
    def __rshift__(self, other: Any) -> ColumnElement[_TE]: ...
    def concat(self, other: Any) -> ColumnElement[sqltypes.String]: ...
    def like(
        self, other: Any, escape: Optional[str] = ...
    ) -> ColumnElement[sqltypes.Boolean]: ...
    def ilike(
        self, other: Any, escape: Optional[str] = ...
    ) -> ColumnElement[sqltypes.Boolean]: ...
    def in_(self, other: Any) -> ColumnElement[sqltypes.Boolean]: ...
    def not_in(self, other: Any) -> ColumnElement[sqltypes.Boolean]: ...
    def not_like(
        self, other: Any, escape: Optional[str] = ...
    ) -> ColumnElement[sqltypes.Boolean]: ...
    def not_ilike(
        self, other: Any, escape: Optional[str] = ...
    ) -> ColumnElement[sqltypes.Boolean]: ...
    def is_(self, other: Any) -> ColumnElement[sqltypes.Boolean]: ...
    def is_not(self, other: Any) -> ColumnElement[sqltypes.Boolean]: ...
    def startswith(
        self, other: Any, **kwargs: Any
    ) -> ColumnElement[sqltypes.Boolean]: ...
    def endswith(
        self, other: Any, **kwargs: Any
    ) -> ColumnElement[sqltypes.Boolean]: ...
    def contains(
        self, other: Any, **kwargs: Any
    ) -> ColumnElement[sqltypes.Boolean]: ...
    def match(
        self, other: Any, **kwargs: Any
    ) -> ColumnElement[sqltypes.Boolean]: ...
    def regexp_match(
        self, pattern: Any, flags: Optional[Any] = ...
    ) -> ColumnElement[sqltypes.Boolean]: ...
    def regexp_replace(
        self, pattern: Any, replacement: Any, flags: Optional[Any] = ...
    ) -> ColumnElement[sqltypes.String]: ...
    def desc(self) -> ColumnElement[sqltypes.NullType]: ...
    def asc(self) -> ColumnElement[sqltypes.NullType]: ...
    def nulls_first(self) -> ColumnElement[sqltypes.NullType]: ...
    def nulls_last(self) -> ColumnElement[sqltypes.NullType]: ...
    def collate(self, collation: str) -> ColumnElement[_TE]: ...
    def __radd__(self, other: Any) -> ColumnElement[_TE]: ...
    def __rsub__(self, other: Any) -> ColumnElement[_TE]: ...
    def __rmul__(self, other: Any) -> ColumnElement[_TE]: ...
    def __rdiv__(self, other: Any) -> ColumnElement[_TE]: ...
    def __rmod__(self, other: Any) -> ColumnElement[_TE]: ...
    def between(
        self, cleft: Any, cright: Any, symmetric: bool = ...
    ) -> ColumnElement[sqltypes.Boolean]: ...
    def distinct(self) -> ColumnElement[_TE]: ...
    def any_(self) -> ColumnElement[sqltypes.NullType]: ...
    def all_(self) -> ColumnElement[sqltypes.NullType]: ...
    def __add__(self, other: Any) -> ColumnElement[_TE]: ...
    def __sub__(self, other: Any) -> ColumnElement[_TE]: ...
    def __mul__(self, other: Any) -> ColumnElement[_TE]: ...
    def __div__(self, other: Any) -> ColumnElement[_TE]: ...
    def __mod__(self, other: Any) -> ColumnElement[_TE]: ...
    def __truediv__(self, other: Any) -> ColumnElement[_TE]: ...
    def __rtruediv__(self, other: Any) -> ColumnElement[_TE]: ...

def commutative_op(fn: _F) -> _F: ...
def comparison_op(fn: _F) -> _F: ...
def from_() -> NoReturn: ...
def function_as_comparison_op() -> NoReturn: ...
def as_() -> NoReturn: ...
def exists() -> NoReturn: ...
def is_true(a: Any) -> NoReturn: ...
def is_false(a: Any) -> NoReturn: ...
def is_distinct_from(a: Any, b: Any) -> ClauseElement: ...
def is_not_distinct_from(a: Any, b: Any) -> ClauseElement: ...
def is_(a: Any, b: Any) -> ClauseElement: ...
def is_not(a: Any, b: Any) -> ClauseElement: ...
def collate(a: Any, b: Any) -> ClauseElement: ...
def op(a: Any, opstring: str, b: Any) -> ClauseElement: ...
def like_op(a: Any, b: Any, escape: Optional[Any] = ...) -> ClauseElement: ...
def not_like_op(
    a: Any, b: Any, escape: Optional[Any] = ...
) -> ClauseElement: ...
def ilike_op(a: Any, b: Any, escape: Optional[Any] = ...) -> ClauseElement: ...
def not_ilike_op(
    a: Any, b: Any, escape: Optional[Any] = ...
) -> ClauseElement: ...
def between_op(
    a: Any, b: Any, c: Any, symmetric: bool = ...
) -> ClauseElement: ...
def not_between_op(
    a: Any, b: Any, c: Any, symmetric: bool = ...
) -> ClauseElement: ...
def in_op(a: Any, b: Any) -> ClauseElement: ...
def not_in_op(a: Any, b: Any) -> ClauseElement: ...
def distinct_op(a: Any) -> ClauseElement: ...
def any_op(a: Any) -> ClauseElement: ...
def all_op(a: Any) -> ClauseElement: ...
def startswith_op(
    a: Any, b: Any, escape: Optional[Any] = ..., autoescape: bool = ...
) -> ClauseElement: ...
def not_startswith_op(
    a: Any, b: Any, escape: Optional[Any] = ..., autoescape: bool = ...
) -> ClauseElement: ...
def endswith_op(
    a: Any, b: Any, escape: Optional[Any] = ..., autoescape: bool = ...
) -> ClauseElement: ...
def not_endswith_op(
    a: Any, b: Any, escape: Optional[Any] = ..., autoescape: bool = ...
) -> ClauseElement: ...
def contains_op(
    a: Any, b: Any, escape: Optional[Any] = ..., autoescape: bool = ...
) -> ClauseElement: ...
def not_contains_op(
    a: Any, b: Any, escape: Optional[Any] = ..., autoescape: bool = ...
) -> ClauseElement: ...
def match_op(a: Any, b: Any, **kw: Any) -> ClauseElement: ...
def regexp_match_op(
    a: Any, b: Any, flags: Optional[Any] = ...
) -> ClauseElement: ...
def not_regexp_match_op(
    a: Any, b: Any, flags: Optional[Any] = ...
) -> ClauseElement: ...
def regexp_replace_op(
    a: Any, b: Any, replacement: Any, flags: Optional[Any] = ...
) -> ClauseElement: ...
def not_match_op(a: Any, b: Any, **kw: Any) -> ClauseElement: ...
def comma_op(a: Any, b: Any) -> NoReturn: ...
def filter_op(a: Any, b: Any) -> NoReturn: ...
def concat_op(a: Any, b: Any) -> ClauseElement: ...
def desc_op(a: Any) -> ClauseElement: ...
def asc_op(a: Any) -> ClauseElement: ...
def nulls_first_op(a: Any) -> ClauseElement: ...
def nulls_last_op(a: Any) -> ClauseElement: ...
def json_getitem_op(a: Any, b: Any) -> NoReturn: ...
def json_path_getitem_op(a: Any, b: Any) -> NoReturn: ...
def is_comparison(op: Any) -> bool: ...
def is_commutative(op: Any) -> bool: ...
def is_ordering_modifier(op: Any) -> bool: ...
def is_natural_self_precedent(op: Any) -> bool: ...
def is_boolean(op: Any) -> bool: ...
def mirror(op: Any) -> Any: ...
def is_associative(op: Any) -> bool: ...
def is_precedent(operator: Any, against: Any) -> bool: ...

# 1.4 deprecated; see sqlalchemy#5435
istrue = is_true
isfalse = is_false
isnot_distinct_from = is_not_distinct_from
isnot = is_not
notlike_op = not_like_op
notilike_op = not_ilike_op
notbetween_op = not_between_op
notin_op = not_in_op
notstartswith_op = not_startswith_op
notendswith_op = not_endswith_op
notcontains_op = not_contains_op
notmatch_op = not_match_op
nullsfirst_op = nulls_first_op
nullslast_op = nulls_last_op
