from datetime import (
    datetime,
    timedelta,
    tzinfo as _tzinfo,
)
from typing import (
    Literal,
    NoReturn,
    Self,
    TypeAlias,
    overload,
)

import numpy as np

from pandas._libs.tslibs.period import Period
from pandas._typing import (
    Frequency,
    TimestampNonexistent,
    TimeUnit,
)

NaT: NaTType
iNaT: int
nat_strings: set[str]

_TimeLike: TypeAlias = datetime | timedelta | Period | np.datetime64 | np.timedelta64
_TimeDelta: TypeAlias = timedelta | np.timedelta64

class NaTType:
    _value: np.int64
    @property
    def value(self) -> int: ...
    @property
    def asm8(self) -> np.datetime64: ...
    def to_datetime64(self) -> np.datetime64: ...
    def to_numpy(
        self, dtype: np.dtype | str | None = ..., copy: bool = ...
    ) -> np.datetime64 | np.timedelta64: ...
    @property
    def is_leap_year(self) -> bool: ...
    @property
    def is_month_start(self) -> bool: ...
    @property
    def is_quarter_start(self) -> bool: ...
    @property
    def is_year_start(self) -> bool: ...
    @property
    def is_month_end(self) -> bool: ...
    @property
    def is_quarter_end(self) -> bool: ...
    @property
    def is_year_end(self) -> bool: ...
    @property
    def day_of_year(self) -> float: ...
    @property
    def dayofyear(self) -> float: ...
    @property
    def days_in_month(self) -> float: ...
    @property
    def daysinmonth(self) -> float: ...
    @property
    def day_of_week(self) -> float: ...
    @property
    def dayofweek(self) -> float: ...
    @property
    def week(self) -> float: ...
    @property
    def weekofyear(self) -> float: ...
    @property
    def fold(self) -> int: ...
    def day_name(self) -> float: ...
    def month_name(self) -> float: ...
    def weekday(self) -> float: ...
    def isoweekday(self) -> float: ...
    def isoformat(self, sep: str = ..., timespec: str = ...) -> str: ...
    def strftime(self, format: str) -> NoReturn: ...
    def total_seconds(self) -> float: ...
    def today(self, *args, **kwargs) -> NaTType: ...
    def now(self, *args, **kwargs) -> NaTType: ...
    def to_pydatetime(self) -> NaTType: ...
    def date(self) -> NaTType: ...
    def round(
        self,
        freq: Frequency,
        ambiguous: bool | Literal["raise"] | NaTType = ...,
        nonexistent: TimestampNonexistent = ...,
    ) -> NaTType: ...
    def floor(
        self,
        freq: Frequency,
        ambiguous: bool | Literal["raise"] | NaTType = ...,
        nonexistent: TimestampNonexistent = ...,
    ) -> NaTType: ...
    def ceil(
        self,
        freq: Frequency,
        ambiguous: bool | Literal["raise"] | NaTType = ...,
        nonexistent: TimestampNonexistent = ...,
    ) -> NaTType: ...
    @property
    def tzinfo(self) -> None: ...
    @property
    def tz(self) -> None: ...
    def tz_convert(self, tz: _tzinfo | str | None) -> NaTType: ...
    def tz_localize(
        self,
        tz: _tzinfo | str | None,
        ambiguous: bool | Literal["raise"] | NaTType = ...,
        nonexistent: TimestampNonexistent = ...,
    ) -> NaTType: ...
    def replace(
        self,
        year: int | None = ...,
        month: int | None = ...,
        day: int | None = ...,
        hour: int | None = ...,
        minute: int | None = ...,
        second: int | None = ...,
        microsecond: int | None = ...,
        nanosecond: int | None = ...,
        tzinfo: _tzinfo | None = ...,
        fold: int | None = ...,
    ) -> NaTType: ...
    @property
    def year(self) -> float: ...
    @property
    def quarter(self) -> float: ...
    @property
    def month(self) -> float: ...
    @property
    def day(self) -> float: ...
    @property
    def hour(self) -> float: ...
    @property
    def minute(self) -> float: ...
    @property
    def second(self) -> float: ...
    @property
    def millisecond(self) -> float: ...
    @property
    def microsecond(self) -> float: ...
    @property
    def nanosecond(self) -> float: ...
    # inject Timedelta properties
    @property
    def days(self) -> float: ...
    @property
    def seconds(self) -> float: ...
    @property
    def microseconds(self) -> float: ...
    @property
    def nanoseconds(self) -> float: ...
    # inject Period properties
    @property
    def qyear(self) -> float: ...
    # comparisons
    def __eq__(self, other: object, /) -> Literal[False]: ...
    def __ne__(self, other: object, /) -> Literal[True]: ...
    def __lt__(self, other: Self | _TimeLike, /) -> Literal[False]: ...
    def __le__(self, other: Self | _TimeLike, /) -> Literal[False]: ...
    def __gt__(self, other: Self | _TimeLike, /) -> Literal[False]: ...
    def __ge__(self, other: Self | _TimeLike, /) -> Literal[False]: ...
    # unary operators
    def __pos__(self) -> Self: ...
    def __neg__(self) -> Self: ...
    # binary operators
    def __sub__(self, other: Self | _TimeLike, /) -> Self: ...
    def __rsub__(self, other: Self | _TimeLike, /) -> Self: ...
    def __add__(self, other: Self | _TimeLike, /) -> Self: ...
    def __radd__(self, other: Self | _TimeLike, /) -> Self: ...
    def __mul__(self, other: float, /) -> Self: ...  # analogous to timedelta
    def __rmul__(self, other: float, /) -> Self: ...
    @overload  # analogous to timedelta
    def __truediv__(self, other: Self | _TimeDelta, /) -> float: ...  # Literal[NaN]
    @overload
    def __truediv__(self, other: float, /) -> Self: ...
    @overload  # analogous to timedelta
    def __floordiv__(self, other: Self | _TimeDelta, /) -> float: ...  # Literal[NaN]
    @overload
    def __floordiv__(self, other: float, /) -> Self: ...
    # other
    def __hash__(self) -> int: ...
    def as_unit(self, unit: TimeUnit, round_ok: bool = ...) -> NaTType: ...
