import datetime as dt
from _typeshed import SupportsAllComparisons
from typing import Any, Generic, TypeVar, overload
from typing_extensions import Self

from psycopg2._psycopg import _type, connection, cursor

_T_co = TypeVar("_T_co", covariant=True)

class Range(Generic[_T_co]):
    __slots__ = ("_lower", "_upper", "_bounds")
    def __init__(
        self, lower: _T_co | None = None, upper: _T_co | None = None, bounds: str = "[)", empty: bool = False
    ) -> None: ...
    @property
    def lower(self) -> _T_co | None: ...
    @property
    def upper(self) -> _T_co | None: ...
    @property
    def isempty(self) -> bool: ...
    @property
    def lower_inf(self) -> bool: ...
    @property
    def upper_inf(self) -> bool: ...
    @property
    def lower_inc(self) -> bool: ...
    @property
    def upper_inc(self) -> bool: ...
    def __contains__(self, x: SupportsAllComparisons) -> bool: ...
    def __bool__(self) -> bool: ...
    def __eq__(self, other: object) -> bool: ...
    def __ne__(self, other: object) -> bool: ...
    def __hash__(self) -> int: ...
    def __lt__(self, other: Range[_T_co]) -> bool: ...
    def __le__(self, other: Range[_T_co]) -> bool: ...
    def __gt__(self, other: Range[_T_co]) -> bool: ...
    def __ge__(self, other: Range[_T_co]) -> bool: ...

def register_range(
    pgrange: str, pyrange: str | type[Range[Any]], conn_or_curs: connection | cursor, globally: bool = False
) -> RangeCaster: ...

class RangeAdapter:
    name: str | None = None
    adapted: Range[Any]
    def __init__(self, adapted: Range[Any]) -> None: ...
    def __conform__(self, proto) -> Self | None: ...
    def prepare(self, conn: connection | None) -> None: ...
    def getquoted(self) -> bytes: ...

class RangeCaster:
    adapter: type[RangeAdapter]
    range: type[Range[Any]]
    subtype_oid: int
    typecaster: _type
    array_typecaster: _type | None
    def __init__(
        self,
        pgrange: str | type[RangeAdapter],
        pyrange: str | type[Range[Any]],
        oid: int,
        subtype_oid: int,
        array_oid: int | None = None,
    ) -> None: ...

    @overload
    def parse(self, s: None, cur: cursor | None = None) -> None: ...
    @overload
    def parse(self, s: str, cur: cursor | None = None) -> Range[Any]: ...
    @overload
    def parse(self, s: str | None, cur: cursor | None = None) -> Range[Any] | None: ...

class NumericRange(Range[float]): ...
class DateRange(Range[dt.date]): ...
class DateTimeRange(Range[dt.datetime]): ...
class DateTimeTZRange(Range[dt.datetime]): ...

class NumberRangeAdapter(RangeAdapter):
    def getquoted(self) -> bytes: ...

int4range_caster: RangeCaster
int8range_caster: RangeCaster
numrange_caster: RangeCaster
daterange_caster: RangeCaster
tsrange_caster: RangeCaster
tstzrange_caster: RangeCaster
