from _typeshed import Incomplete, StrOrBytesPath
from collections.abc import Buffer, Iterable, Sequence
from typing import (
    Any,
    ClassVar,
    Literal,
    Protocol,
    SupportsIndex,
    overload,
    type_check_only,
)
from typing_extensions import TypeVar

import numpy as np
from numpy import _ByteOrder, _OrderKACF
from numpy._typing import (
    ArrayLike,
    DTypeLike,
    NDArray,
    _AnyShape,
    _ArrayLikeVoid_co,
    _NestedSequence,
    _Shape,
    _ShapeLike,
)

__all__ = [
    "array",
    "find_duplicate",
    "format_parser",
    "fromarrays",
    "fromfile",
    "fromrecords",
    "fromstring",
    "recarray",
    "record",
]

# Explicit covariant type variables are needed because mypy isn't very good at variance inference right now.
_DTypeT_co = TypeVar("_DTypeT_co", bound=np.dtype, default=np.dtype, covariant=True)
_ShapeT_co = TypeVar("_ShapeT_co", bound=_Shape, default=_AnyShape, covariant=True)

type _RecArray[_ScalarT: np.generic] = recarray[_AnyShape, np.dtype[_ScalarT]]

@type_check_only
class _SupportsReadInto(Protocol):
    def seek(self, offset: int, whence: int, /) -> object: ...
    def tell(self, /) -> int: ...
    def readinto(self, buffer: memoryview, /) -> int: ...

###

# exported in `numpy.rec`
class record(np.void):  # type: ignore[misc]
    __name__: ClassVar[Literal["record"]] = "record"
    __module__: Literal["numpy"] = "numpy"  # pyrefly: ignore[bad-override]

    def pprint(self) -> str: ...

    def __getattribute__(self, attr: str, /) -> Any: ...
    def __setattr__(self, attr: str, val: ArrayLike, /) -> None: ...

    #
    @overload  # type: ignore[override]
    def __getitem__(self, key: str | SupportsIndex, /) -> Incomplete: ...  # pyrefly: ignore[bad-override]
    @overload
    def __getitem__(self, key: list[str], /) -> record: ...

# exported in `numpy.rec`
class recarray(np.ndarray[_ShapeT_co, _DTypeT_co]):
    __name__: ClassVar[Literal["recarray"]] = "recarray"
    __module__: Literal["numpy.rec"] = "numpy.rec"  # pyrefly: ignore[bad-override]

    @overload
    def __new__(
        cls,
        shape: _ShapeLike,
        dtype: None = None,
        buf: Buffer | None = None,
        offset: SupportsIndex = 0,
        strides: _ShapeLike | None = None,
        *,
        formats: DTypeLike | None,
        names: str | Sequence[str] | None = None,
        titles: str | Sequence[str] | None = None,
        byteorder: _ByteOrder | None = None,
        aligned: bool = False,
        order: _OrderKACF = "C",
    ) -> _RecArray[record]: ...
    @overload
    def __new__(
        cls,
        shape: _ShapeLike,
        dtype: DTypeLike | None,
        buf: Buffer | None = None,
        offset: SupportsIndex = 0,
        strides: _ShapeLike | None = None,
        formats: None = None,
        names: None = None,
        titles: None = None,
        byteorder: None = None,
        aligned: Literal[False] = False,
        order: _OrderKACF = "C",
    ) -> _RecArray[Incomplete]: ...

    def __getattribute__(self, attr: str, /) -> Any: ...
    def __setattr__(self, attr: str, val: ArrayLike, /) -> None: ...

    def __array_finalize__(self, /, obj: object) -> None: ...

    #
    @overload
    def field(self, /, attr: int | str, val: ArrayLike) -> None: ...
    @overload
    def field(self, /, attr: int | str, val: None = None) -> Incomplete: ...

# exported in `numpy.rec`
class format_parser:
    dtype: np.dtype[np.void]
    def __init__(
        self,
        /,
        formats: DTypeLike | None,
        names: str | Sequence[str] | None,
        titles: str | Sequence[str] | None,
        aligned: bool = False,
        byteorder: _ByteOrder | None = None,
    ) -> None: ...

# exported in `numpy.rec`
@overload
def fromarrays(
    arrayList: Iterable[ArrayLike],
    dtype: DTypeLike | None = None,
    shape: _ShapeLike | None = None,
    formats: None = None,
    names: None = None,
    titles: None = None,
    aligned: bool = False,
    byteorder: None = None,
) -> _RecArray[Any]: ...
@overload
def fromarrays(
    arrayList: Iterable[ArrayLike],
    dtype: None = None,
    shape: _ShapeLike | None = None,
    formats: DTypeLike | None = None,
    names: str | Sequence[str] | None = None,
    titles: str | Sequence[str] | None = None,
    aligned: bool = False,
    byteorder: _ByteOrder | None = None,
) -> _RecArray[record]: ...

# exported in `numpy.rec`
@overload
def fromrecords(
    recList: _ArrayLikeVoid_co | tuple[object, ...] | _NestedSequence[tuple[object, ...]],
    dtype: DTypeLike | None = None,
    shape: _ShapeLike | None = None,
    formats: None = None,
    names: None = None,
    titles: None = None,
    aligned: bool = False,
    byteorder: None = None,
) -> _RecArray[record]: ...
@overload
def fromrecords(
    recList: _ArrayLikeVoid_co | tuple[object, ...] | _NestedSequence[tuple[object, ...]],
    dtype: None = None,
    shape: _ShapeLike | None = None,
    formats: DTypeLike | None = None,
    names: str | Sequence[str] | None = None,
    titles: str | Sequence[str] | None = None,
    aligned: bool = False,
    byteorder: _ByteOrder | None = None,
) -> _RecArray[record]: ...

# exported in `numpy.rec`
@overload
def fromstring(
    datastring: Buffer,
    dtype: DTypeLike | None,
    shape: _ShapeLike | None = None,
    offset: int = 0,
    formats: None = None,
    names: None = None,
    titles: None = None,
    aligned: bool = False,
    byteorder: None = None,
) -> _RecArray[record]: ...
@overload
def fromstring(
    datastring: Buffer,
    dtype: None = None,
    shape: _ShapeLike | None = None,
    offset: int = 0,
    *,
    formats: DTypeLike | None,
    names: str | Sequence[str] | None = None,
    titles: str | Sequence[str] | None = None,
    aligned: bool = False,
    byteorder: _ByteOrder | None = None,
) -> _RecArray[record]: ...

# exported in `numpy.rec`
@overload
def fromfile(
    fd: StrOrBytesPath | _SupportsReadInto,
    dtype: DTypeLike | None,
    shape: _ShapeLike | None = None,
    offset: int = 0,
    formats: None = None,
    names: None = None,
    titles: None = None,
    aligned: bool = False,
    byteorder: None = None,
) -> _RecArray[Any]: ...
@overload
def fromfile(
    fd: StrOrBytesPath | _SupportsReadInto,
    dtype: None = None,
    shape: _ShapeLike | None = None,
    offset: int = 0,
    *,
    formats: DTypeLike | None,
    names: str | Sequence[str] | None = None,
    titles: str | Sequence[str] | None = None,
    aligned: bool = False,
    byteorder: _ByteOrder | None = None,
) -> _RecArray[record]: ...

# exported in `numpy.rec`
@overload
def array[ScalarT: np.generic](
    obj: ScalarT | NDArray[ScalarT],
    dtype: None = None,
    shape: _ShapeLike | None = None,
    offset: int = 0,
    strides: tuple[int, ...] | None = None,
    formats: None = None,
    names: None = None,
    titles: None = None,
    aligned: bool = False,
    byteorder: None = None,
    copy: bool = True,
) -> _RecArray[ScalarT]: ...
@overload
def array(
    obj: ArrayLike,
    dtype: DTypeLike | None,
    shape: _ShapeLike | None = None,
    offset: int = 0,
    strides: tuple[int, ...] | None = None,
    formats: None = None,
    names: None = None,
    titles: None = None,
    aligned: bool = False,
    byteorder: None = None,
    copy: bool = True,
) -> _RecArray[Any]: ...
@overload
def array(
    obj: ArrayLike,
    dtype: None = None,
    shape: _ShapeLike | None = None,
    offset: int = 0,
    strides: tuple[int, ...] | None = None,
    *,
    formats: DTypeLike | None,
    names: str | Sequence[str] | None = None,
    titles: str | Sequence[str] | None = None,
    aligned: bool = False,
    byteorder: _ByteOrder | None = None,
    copy: bool = True,
) -> _RecArray[record]: ...
@overload
def array(
    obj: None,
    dtype: DTypeLike | None,
    shape: _ShapeLike,
    offset: int = 0,
    strides: tuple[int, ...] | None = None,
    formats: None = None,
    names: None = None,
    titles: None = None,
    aligned: bool = False,
    byteorder: None = None,
    copy: bool = True,
) -> _RecArray[Any]: ...
@overload
def array(
    obj: None,
    dtype: None = None,
    *,
    shape: _ShapeLike,
    offset: int = 0,
    strides: tuple[int, ...] | None = None,
    formats: DTypeLike | None,
    names: str | Sequence[str] | None = None,
    titles: str | Sequence[str] | None = None,
    aligned: bool = False,
    byteorder: _ByteOrder | None = None,
    copy: bool = True,
) -> _RecArray[record]: ...
@overload
def array(
    obj: _SupportsReadInto,
    dtype: DTypeLike | None,
    shape: _ShapeLike | None = None,
    offset: int = 0,
    strides: tuple[int, ...] | None = None,
    formats: None = None,
    names: None = None,
    titles: None = None,
    aligned: bool = False,
    byteorder: None = None,
    copy: bool = True,
) -> _RecArray[Any]: ...
@overload
def array(
    obj: _SupportsReadInto,
    dtype: None = None,
    shape: _ShapeLike | None = None,
    offset: int = 0,
    strides: tuple[int, ...] | None = None,
    *,
    formats: DTypeLike | None,
    names: str | Sequence[str] | None = None,
    titles: str | Sequence[str] | None = None,
    aligned: bool = False,
    byteorder: _ByteOrder | None = None,
    copy: bool = True,
) -> _RecArray[record]: ...

# exported in `numpy.rec`
def find_duplicate[T](list: Iterable[T]) -> list[T]: ...
