from collections.abc import (
    Hashable,
    Sequence,
)
from datetime import (
    datetime,
    time,
    timedelta,
    tzinfo as _tzinfo,
)
from typing import (
    Literal,
    Never,
    Self,
    final,
    overload,
)

import numpy as np
import pandas as pd
from pandas.core.frame import DataFrame
from pandas.core.indexes.accessors import DatetimeIndexProperties
from pandas.core.indexes.base import Index
from pandas.core.indexes.datetimelike import DatetimeTimedeltaMixin
from pandas.core.indexes.timedeltas import TimedeltaIndex
from pandas.core.series import Series

from pandas._libs.tslibs.timestamps import Timestamp
from pandas._typing import (
    AxesData,
    DateAndDatetimeLike,
    Frequency,
    IntervalClosedType,
    TimeUnit,
    TimeZones,
    np_1darray_intp,
    np_ndarray,
    np_ndarray_bool,
    np_ndarray_dt,
    np_ndarray_td,
)

from pandas.core.dtypes.dtypes import DatetimeTZDtype

from pandas.tseries.offsets import BaseOffset

class DatetimeIndex(
    DatetimeTimedeltaMixin[Timestamp, np.datetime64], DatetimeIndexProperties
):
    def __new__(
        cls,
        data: AxesData,
        freq: Frequency = ...,
        tz: TimeZones = ...,
        ambiguous: Literal["infer", "NaT", "raise"] | np_ndarray_bool = "raise",
        dayfirst: bool = False,
        yearfirst: bool = False,
        dtype: np.dtype[np.datetime64] | pd.DatetimeTZDtype | str | None = None,
        copy: bool = False,
        name: Hashable = None,
    ) -> Self: ...

    # various ignores needed for mypy, as we do want to restrict what can be used in
    # arithmetic for these types
    def __add__(  # type: ignore[override] # pyright: ignore[reportIncompatibleMethodOverride] # pyrefly: ignore[bad-override] # ty: ignore[invalid-method-override]
        self, other: timedelta | BaseOffset
    ) -> Self: ...
    def __radd__(  # type: ignore[override] # pyright: ignore[reportIncompatibleMethodOverride] # ty: ignore[invalid-method-override]
        self, other: timedelta | BaseOffset
    ) -> Self: ...
    @overload  # type: ignore[override]
    def __sub__(  # pyrefly: ignore[bad-override]
        self, other: datetime | np.datetime64 | np_ndarray_dt | Self
    ) -> TimedeltaIndex: ...
    @overload
    def __sub__(  # pyright: ignore[reportIncompatibleMethodOverride] # ty: ignore[invalid-method-override]
        self, other: timedelta | np.timedelta64 | np_ndarray_td | BaseOffset
    ) -> Self: ...
    def __truediv__(self, other: np_ndarray) -> Never: ...  # type: ignore[override]
    def __rtruediv__(self, other: np_ndarray) -> Never: ...  # type: ignore[override]
    @final
    def to_series(
        self, index: Index | None = None, name: Hashable | None = None
    ) -> Series[Timestamp]: ...
    def snap(self, freq: Frequency = "S") -> Self: ...
    @property
    def inferred_type(self) -> str: ...
    def indexer_at_time(
        self, time: str | time, asof: bool = False
    ) -> np_1darray_intp: ...
    def indexer_between_time(
        self,
        start_time: time | str,
        end_time: time | str,
        include_start: bool = True,
        include_end: bool = True,
    ) -> np_1darray_intp: ...
    def to_julian_date(self) -> Index[float]:
        """
Convert Datetime Array to float64 ndarray of Julian Dates.
0 Julian date is noon January 1, 4713 BC.
https://en.wikipedia.org/wiki/Julian_day
        """
        pass
    def isocalendar(self) -> DataFrame:
        """
Calculate year, week, and day according to the ISO 8601 standard.

Returns
-------
DataFrame
    With columns year, week and day.

See Also
--------
Timestamp.isocalendar : Function return a 3-tuple containing ISO year,
    week number, and weekday for the given Timestamp object.
datetime.date.isocalendar : Return a named tuple object with
    three components: year, week and weekday.

Examples
--------
>>> idx = pd.date_range(start='2019-12-29', freq='D', periods=4)
>>> idx.isocalendar()
            year  week  day
2019-12-29  2019    52    7
2019-12-30  2020     1    1
2019-12-31  2020     1    2
2020-01-01  2020     1    3
>>> idx.isocalendar().week
2019-12-29    52
2019-12-30     1
2019-12-31     1
2020-01-01     1
Freq: D, Name: week, dtype: UInt32
        """
        pass
    @property
    def tzinfo(self) -> _tzinfo | None: ...
    @property
    def dtype(self) -> np.dtype | DatetimeTZDtype: ...
    def shift(
        self, periods: int = 1, freq: Frequency | timedelta | None = None
    ) -> Self: ...

@overload
def date_range(
    start: str | DateAndDatetimeLike,
    end: str | DateAndDatetimeLike,
    freq: Frequency | timedelta | None = None,
    tz: TimeZones = None,
    normalize: bool = False,
    name: Hashable = None,
    inclusive: IntervalClosedType = "both",
    unit: TimeUnit | None = None,
) -> DatetimeIndex: ...
@overload
def date_range(
    start: str | DateAndDatetimeLike,
    end: str | DateAndDatetimeLike,
    periods: int,
    tz: TimeZones = None,
    normalize: bool = False,
    name: Hashable = None,
    inclusive: IntervalClosedType = "both",
    unit: TimeUnit | None = None,
) -> DatetimeIndex: ...
@overload
def date_range(
    start: str | DateAndDatetimeLike,
    *,
    periods: int,
    freq: Frequency | timedelta | None = None,
    tz: TimeZones = None,
    normalize: bool = False,
    name: Hashable = None,
    inclusive: IntervalClosedType = "both",
    unit: TimeUnit | None = None,
) -> DatetimeIndex: ...
@overload
def date_range(
    *,
    end: str | DateAndDatetimeLike,
    periods: int,
    freq: Frequency | timedelta | None = None,
    tz: TimeZones = None,
    normalize: bool = False,
    name: Hashable = None,
    inclusive: IntervalClosedType = "both",
    unit: TimeUnit | None = None,
) -> DatetimeIndex: ...
@overload
def bdate_range(
    start: str | DateAndDatetimeLike | None = None,
    end: str | DateAndDatetimeLike | None = None,
    periods: int | None = None,
    freq: Frequency | timedelta = "B",
    tz: TimeZones = None,
    normalize: bool = False,
    name: Hashable = None,
    weekmask: str | None = None,
    holidays: None = None,
    inclusive: IntervalClosedType = "both",
) -> DatetimeIndex: ...
@overload
def bdate_range(
    start: str | DateAndDatetimeLike | None = None,
    end: str | DateAndDatetimeLike | None = None,
    periods: int | None = None,
    *,
    freq: Frequency | timedelta,
    tz: TimeZones = None,
    normalize: bool = False,
    name: Hashable = None,
    weekmask: str | None = None,
    holidays: Sequence[str | DateAndDatetimeLike],
    inclusive: IntervalClosedType = "both",
) -> DatetimeIndex: ...
