import types
from datetime import date, datetime, time
from decimal import Decimal
from typing import (
    IO,
    Any,
    Iterable,
    Iterator,
    List,
    Mapping,
    Optional,
    Sequence,
    Tuple,
    Type,
    Union,
)
from uuid import UUID

import psycopg2
from django.db.backends.postgresql.base import DatabaseWrapper
from psycopg2.extensions import Column
from typing_extensions import Literal

logger: Any

# Python types that can be adapted to SQL.
_Mixed = Union[None, bool, int, float, Decimal, str, bytes, datetime, UUID]
_SQLType = Union[_Mixed, Sequence[_Mixed], Mapping[str, _Mixed]]

class CursorWrapper:
    cursor: psycopg2.extensions.cursor = ...
    db: DatabaseWrapper = ...
    def __init__(
        self, cursor: psycopg2.extensions.cursor, db: DatabaseWrapper
    ) -> None: ...
    WRAP_ERROR_ATTRS: Any = ...
    def __iter__(self) -> Iterator[Tuple[Any, ...]]: ...
    def __next__(self) -> Tuple[Any, ...]: ...
    def __enter__(self) -> CursorWrapper: ...
    def __exit__(
        self,
        exc_type: Optional[Type[BaseException]],
        exc_value: Optional[BaseException],
        tb: Optional[types.TracebackType],
    ) -> None: ...
    def callproc(
        self,
        procname: str,
        params: Optional[Sequence[_SQLType]] = ...,
        kparams: Optional[Mapping[str, int]] = ...,
    ) -> None: ...
    def execute(
        self,
        sql: str,
        params: Optional[Union[Sequence[_SQLType], Mapping[str, _SQLType]]] = ...,
    ) -> None: ...
    def executemany(
        self,
        sql: str,
        param_list: Sequence[
            Optional[Union[Sequence[_SQLType], Mapping[str, _SQLType]]]
        ],
    ) -> None: ...
    # copied over from psycopg2 since Django uses __getattr__ to proxy calls
    @property
    def description(self) -> Optional[Tuple[Column, ...]]: ...
    def close(self) -> None: ...
    @property
    def closed(self) -> bool: ...
    @property
    def connection(self) -> psycopg2.extensions.connection: ...
    @property
    def name(self) -> Optional[str]: ...
    scrollable: Optional[bool]
    withhold: bool
    def mogrify(
        self,
        operation: str,
        parameters: Optional[Union[Sequence[_SQLType], Mapping[str, _SQLType]]] = ...,
    ) -> bytes: ...
    def setinputsizes(self, sizes: int) -> None: ...
    def fetchone(self) -> Optional[Tuple[Any, ...]]: ...
    def fetchmany(self, size: int = ...) -> List[Tuple[Any, ...]]: ...
    def fetchall(self) -> List[Tuple[Any, ...]]: ...
    def scroll(
        self, value: int, mode: Union[Literal["relative"], Literal["absolute"]] = ...
    ) -> None: ...
    arraysize: int
    itersize: int
    @property
    def rowcount(self) -> int: ...
    @property
    def rownumber(self) -> int: ...
    @property
    def lastrowid(self) -> Optional[int]: ...
    @property
    def query(self) -> Optional[str]: ...
    @property
    def statusmessage(self) -> Optional[str]: ...
    def cast(self, oid: int, s: str) -> Any: ...
    tzinfo_factory: Any
    def nextset(self) -> None: ...
    def setoutputsize(self, size: int, column: int = ...) -> None: ...
    def copy_from(
        self,
        file: IO[str],
        table: str,
        sep: str = ...,
        null: str = ...,
        size: int = ...,
        columns: Optional[Iterable[str]] = ...,
    ) -> None: ...
    def copy_to(
        self,
        file: IO[str],
        table: str,
        sep: str = ...,
        null: str = ...,
        columns: Optional[str] = ...,
    ) -> None: ...
    def copy_expert(self, sql: str, file: IO[str], size: int = ...) -> None: ...

class CursorDebugWrapper(CursorWrapper):
    cursor: Any
    db: Any

def typecast_date(s: Optional[str]) -> Optional[date]: ...
def typecast_time(s: Optional[str]) -> Optional[time]: ...
def typecast_timestamp(s: Optional[str]) -> Optional[date]: ...
def rev_typecast_decimal(d: Decimal) -> str: ...
def split_identifier(identifier: str) -> Tuple[str, str]: ...
def truncate_name(
    identifier: str, length: Optional[int] = ..., hash_len: int = ...
) -> str: ...
def format_number(
    value: Optional[Decimal], max_digits: Optional[int], decimal_places: Optional[int]
) -> Optional[str]: ...
def strip_quotes(table_name: str) -> str: ...
