from typing import Any
from typing import Optional
from typing import TypeVar
from typing import Union

from . import roles
from .base import CompileState
from .base import DialectKWArgs
from .base import Executable
from .base import HasCompileState
from .base import ImmutableColumnCollection
from .elements import BooleanClauseList
from .elements import ClauseElement
from .schema import Table
from .selectable import HasCTE
from .selectable import HasPrefixes

_UB = TypeVar("_UB", bound=UpdateBase)
_VB = TypeVar("_VB", bound=ValuesBase)
_I = TypeVar("_I", bound=Insert)
_DWB = TypeVar("_DWB", bound=DMLWhereBase)
_UD = TypeVar("_UD", bound=Update)

class DMLState(CompileState):
    isupdate: bool = ...
    isdelete: bool = ...
    isinsert: bool = ...
    def __init__(self, statement: Any, compiler: Any, **kw: Any) -> None: ...
    @property
    def dml_table(self) -> Table: ...

class InsertDMLState(DMLState):
    isinsert: bool = ...
    include_table_with_column_exprs: bool = ...
    statement: Any = ...
    def __init__(self, statement: Any, compiler: Any, **kw: Any) -> None: ...

class UpdateDMLState(DMLState):
    isupdate: bool = ...
    include_table_with_column_exprs: bool = ...
    statement: Any = ...
    is_multitable: bool = ...
    def __init__(self, statement: Any, compiler: Any, **kw: Any) -> None: ...

class DeleteDMLState(DMLState):
    isdelete: bool = ...
    statement: Any = ...
    def __init__(self, statement: Any, compiler: Any, **kw: Any) -> None: ...

class UpdateBase(
    roles.DMLRole,
    HasCTE,
    HasCompileState,
    DialectKWArgs,
    HasPrefixes,
    Executable,
    ClauseElement,
):
    __visit_name__: str = ...
    named_with_column: bool = ...
    is_dml: bool = ...
    bind: Any = ...
    def params(self: _UB, *arg: Any, **kw: Any) -> _UB: ...
    def with_dialect_options(self: _UB, **opt: Any) -> _UB: ...
    def returning(self: _UB, *cols: Any) -> _UB: ...
    @property
    def exported_columns(self) -> ImmutableColumnCollection[Any]: ...
    def with_hint(
        self: _UB,
        text: Any,
        selectable: Optional[Any] = ...,
        dialect_name: str = ...,
    ) -> _UB: ...

class ValuesBase(UpdateBase):
    __visit_name__: str = ...
    select: Any = ...
    table: Any = ...
    def __init__(self, table: Any, values: Any, prefixes: Any) -> None: ...
    def values(self: _VB, *args: Any, **kwargs: Any) -> _VB: ...
    def return_defaults(self: _VB, *cols: Any) -> _VB: ...

class Insert(ValuesBase):
    __visit_name__: str = ...
    select: Any = ...
    include_insert_from_select_defaults: bool = ...
    is_insert: bool = ...
    def __init__(
        self,
        table: Any,
        values: Optional[Any] = ...,
        inline: bool = ...,
        bind: Optional[Any] = ...,
        prefixes: Optional[Any] = ...,
        returning: Optional[Any] = ...,
        return_defaults: bool = ...,
        **dialect_kw: Any,
    ) -> None: ...
    def inline(self: _I) -> _I: ...
    def from_select(
        self: _I, names: Any, select: Any, include_defaults: bool = ...
    ) -> _I: ...

class DMLWhereBase:
    def where(self: _DWB, *whereclause: Any) -> _DWB: ...
    def filter(self: _DWB, *criteria: Any) -> _DWB: ...
    def filter_by(self: _DWB, **kwargs: Any) -> _DWB: ...
    @property
    def whereclause(
        self,
    ) -> Optional[Union[BooleanClauseList[Any], ClauseElement]]: ...

class Update(DMLWhereBase, ValuesBase):
    __visit_name__: str = ...
    is_update: bool = ...
    def __init__(
        self,
        table: Any,
        whereclause: Optional[Any] = ...,
        values: Optional[Any] = ...,
        inline: bool = ...,
        bind: Optional[Any] = ...,
        prefixes: Optional[Any] = ...,
        returning: Optional[Any] = ...,
        return_defaults: bool = ...,
        preserve_parameter_order: bool = ...,
        **dialect_kw: Any,
    ) -> None: ...
    def ordered_values(self: _UD, *args: Any) -> _UD: ...
    def inline(self: _UD) -> _UD: ...

class Delete(DMLWhereBase, UpdateBase):
    __visit_name__: str = ...
    is_delete: bool = ...
    table: Any = ...
    def __init__(
        self,
        table: Any,
        whereclause: Optional[Any] = ...,
        bind: Optional[Any] = ...,
        returning: Optional[Any] = ...,
        prefixes: Optional[Any] = ...,
        **dialect_kw: Any,
    ) -> None: ...
