from collections.abc import Iterator
from typing import (
    Any,
    overload,
)

import numpy as np
from typing_extensions import Self

from pandas._typing import (
    ArrayLike,
    Scalar,
    ScalarIndexer,
    SequenceIndexer,
    TakeIndexer,
    np_1darray,
    npt,
)

from pandas.core.dtypes.dtypes import ExtensionDtype as ExtensionDtype

class ExtensionArray:
    @overload
    def __getitem__(self, item: ScalarIndexer) -> Any: ...
    @overload
    def __getitem__(self, item: SequenceIndexer) -> Self: ...
    def __setitem__(self, key: int | slice | np.ndarray, value: Any) -> None: ...
    def __len__(self) -> int: ...
    def __iter__(self) -> Iterator[Any]: ...
    def __contains__(self, item: object) -> bool | np.bool_: ...
    def to_numpy(
        self,
        dtype: npt.DTypeLike | None = ...,
        copy: bool = False,
        na_value: Scalar = ...,
    ) -> np_1darray[Any]: ...
    @property
    def dtype(self) -> ExtensionDtype: ...
    @property
    def shape(self) -> tuple[int, ...]: ...
    @property
    def ndim(self) -> int: ...
    @property
    def nbytes(self) -> int: ...
    def astype(self, dtype, copy: bool = True): ...
    def isna(self) -> ArrayLike: ...
    def argsort(
        self, *, ascending: bool = ..., kind: str = ..., **kwargs
    ) -> np_1darray: ...
    def fillna(self, value=..., method=None, limit=None): ...
    def dropna(self): ...
    def shift(self, periods: int = 1, fill_value: object = ...) -> Self: ...
    def unique(self): ...
    def searchsorted(self, value, side: str = ..., sorter=...): ...
    def factorize(self, use_na_sentinel: bool = True) -> tuple[np_1darray, Self]: ...
    def repeat(self, repeats, axis=...): ...
    def take(
        self,
        indexer: TakeIndexer,
        *,
        allow_fill: bool = ...,
        fill_value=...,
    ) -> Self: ...
    def copy(self) -> Self: ...
    def view(self, dtype=...) -> Self | np_1darray: ...
    def ravel(self, order="C") -> Self: ...
    def tolist(self) -> list: ...
    def _reduce(
        self, name: str, *, skipna: bool = ..., keepdims: bool = ..., **kwargs
    ) -> object: ...
    def _accumulate(self, name: str, *, skipna: bool = ..., **kwargs) -> Self: ...

class ExtensionOpsMixin:
    @classmethod
    def _add_arithmetic_ops(cls) -> None: ...
    @classmethod
    def _add_comparison_ops(cls) -> None: ...
    @classmethod
    def _add_logical_ops(cls) -> None: ...

class ExtensionScalarOpsMixin(ExtensionOpsMixin): ...
