"""Mypy stubs for pdcast/types/array/object.pyx"""
from typing import Any, Iterable, Iterator, NoReturn

import numpy as np
import pandas as pd
from pandas.core.arrays import ExtensionArray
from pandas.core.dtypes.base import ExtensionDtype

from pdcast.types import ScalarType
from pdcast.util.type_hints import dtype_like


boolean_array = np.ndarray[np.bool_, np.dtype[np.bool_]]


def construct_object_dtype(
    pdcast_type: ScalarType,
    is_boolean: bool,
    is_numeric: bool,
    kind: str = ...,
    nullable: bool = ...,
    common_dtype: dtype_like | None = ...,
) -> ObjectDtype:
    ...
def construct_array_type(pdcast_type: ScalarType) -> type[ExtensionArray]: ...


class ObjectDtype(ExtensionDtype):
    def __init__(self) -> None: ...
    @classmethod
    def construct_from_string(cls, string: str) -> NoReturn: ...
    def __getattr__(self, name: str) -> Any: ...
    def __dir__(self) -> list[str]: ...
    def __repr__(self) -> str: ...


class _ObjectDtype(ObjectDtype):
    _pdcast_type: ScalarType
    name: str
    type: type
    kind: str
    na_value: Any
    _is_boolean: bool
    _is_numeric: bool
    _can_hold_na: bool

    @classmethod
    def construct_array_type(cls) -> type[ExtensionArray]: ...
    def _get_common_dtype(self, dtypes: Iterable[ExtensionDtype]) -> dtype_like | None: ...


class ObjectArray(ExtensionArray):
    __array_priority__: int

    def __init__(
        self, values: Iterable[Any], dtype: dtype_like | None = ..., copy: bool = ...
    ) -> None:
        ...

    ############################
    ####    CONSTRUCTORS    ####
    ############################

    @classmethod
    def _from_sequence(
        cls, scalars: Iterable[Any], dtype: dtype_like | None = ..., copy: bool = ...
    ) -> ObjectArray:
        ...
    @classmethod
    def _from_factorized(
        cls, values: np.ndarray, original: ExtensionArray
    ) -> ObjectArray:
        ...
    @classmethod
    def _concat_same_type(
        cls, to_concat: Iterable[ExtensionArray]
    ) -> ObjectArray:
        ...

    ##########################
    ####    ATTRIBUTES    ####
    ##########################

    @property
    def dtype(self) -> ObjectDtype: ...
    @property
    def _dtype(self) -> ObjectDtype: ...
    @property
    def nbytes(self) -> int: ...

    ########################
    ####    INTERNAL    ####
    ########################

    def _values_for_argsort(self) -> np.ndarray: ...
    def _values_for_factorize(self) -> tuple[np.ndarray, ObjectArray]: ...
    def _reduce(self, name: str, skipna: bool = ..., **kwargs: Any) -> Any: ...
    def __array_ufunc__(
        self, ufunc: np.ufunc, method: str, *inputs: Any, **kwargs: Any
    ) -> ObjectArray:
        ...
    def __arrow_array__(self, type: dtype_like | None = ...) -> Any: ...
    def __from_arrow__(self, array: Any) -> ObjectArray: ...

    ######################
    ####    PUBLIC    ####
    ######################

    def astype(self, dtype: dtype_like, copy: bool = ...) -> ObjectArray: ...
    def isna(self) -> boolean_array: ...
    def take(
        self,
        indices: Iterable[int],
        allow_fill: bool = ...,
        fill_value: Any | None = ...
    ) -> ObjectArray:
        ...
    def copy(self) -> ObjectArray: ...

    ############################
    ####    NEW METHODS    ####
    ############################

    def round(self, *args: Any, **kwargs: Any) -> ObjectArray: ...
    def value_counts(self, dropna: bool = ...) -> pd.Series: ...

    ###############################
    ####    UNARY OPERATORS    ####
    ###############################

    def __abs__(self) -> ObjectArray: ...
    def __neg__(self) -> ObjectArray: ...
    def __pos__(self) -> ObjectArray: ...
    def __invert__(self) -> ObjectArray: ...

    ################################
    ####    BINARY OPERATORS    ####
    ################################

    def __and__(self, other: Any) -> ObjectArray: ...
    def __or__(self, other: Any) -> ObjectArray: ...
    def __xor__(self, other: Any) -> ObjectArray: ...
    def __rshift__(self, other: Any) -> ObjectArray: ...
    def __lshift__(self, other: Any) -> ObjectArray: ...

    ########################################
    ####    REVERSE BINARY OPERATORS    ####
    ########################################

    def __rand__(self, other: Any) -> ObjectArray: ...
    def __ror__(self, other: Any) -> ObjectArray: ...
    def __rxor__(self, other: Any) -> ObjectArray: ...
    def __rrshift__(self, other: Any) -> ObjectArray: ...
    def __rlshift__(self, other: Any) -> ObjectArray: ...

    #########################################
    ####    IN-PLACE BINARY OPERATORS    ####
    #########################################

    def __iand__(self, other: Any) -> ObjectArray: ...
    def __ior__(self, other: Any) -> ObjectArray: ...
    def __ixor__(self, other: Any) -> ObjectArray: ...
    def __irshift__(self, other: Any) -> ObjectArray: ...
    def __ilshift__(self, other: Any) -> ObjectArray: ...

    ##############################
    ####    MATH OPERATORS    ####
    ##############################

    def __add__(self, other: Any) -> ObjectArray: ...
    def __sub__(self, other: Any) -> ObjectArray: ...
    def __mul__(self, other: Any) -> ObjectArray: ...
    def __matmul__(self, other: Any) -> ObjectArray: ...
    def __truediv__(self, other: Any) -> ObjectArray: ...
    def __floordiv__(self, other: Any) -> ObjectArray: ...
    def __mod__(self, other: Any) -> ObjectArray: ...
    def __divmod__(self, other: Any) -> ObjectArray: ...
    def __pow__(self, other: Any, mod: Any | None = ...) -> ObjectArray: ...

    ######################################
    ####    REVERSE MATH OPERATORS    ####
    ######################################

    def __radd__(self, other: Any) -> ObjectArray: ...
    def __rsub__(self, other: Any) -> ObjectArray: ...
    def __rmul__(self, other: Any) -> ObjectArray: ...
    def __rmatmul__(self, other: Any) -> ObjectArray: ...
    def __rtruediv__(self, other: Any) -> ObjectArray: ...
    def __rfloordiv__(self, other: Any) -> ObjectArray: ...
    def __rmod__(self, other: Any) -> ObjectArray: ...
    def __rdivmod__(self, other: Any) -> ObjectArray: ...
    def __rpow__(self, other: Any, mod: Any | None = ...) -> ObjectArray: ...

    #######################################
    ####    IN-PLACE MATH OPERATORS    ####
    #######################################

    def __iadd__(self, other: Any) -> ObjectArray: ...
    def __isub__(self, other: Any) -> ObjectArray: ...
    def __imul__(self, other: Any) -> ObjectArray: ...
    def __imatmul__(self, other: Any) -> ObjectArray: ...
    def __itruediv__(self, other: Any) -> ObjectArray: ...
    def __ifloordiv__(self, other: Any) -> ObjectArray: ...
    def __imod__(self, other: Any) -> ObjectArray: ...
    def __ipow__(self, other: Any, mod: Any | None = ...) -> ObjectArray: ...

    ####################################
    ####    COMPARISON OPERATORS    ####
    ####################################

    def __lt__(self, other: Any) -> boolean_array: ...
    def __le__(self, other: Any) -> boolean_array: ...
    def __eq__(self, other: Any) -> boolean_array: ...
    def __ne__(self, other: Any) -> boolean_array: ...
    def __gt__(self, other: Any) -> boolean_array: ...
    def __ge__(self, other: Any) -> boolean_array: ...

    #################################
    ####    CONTAINER METHODS    ####
    #################################

    def __getitem__(self, key: Any) -> Any | ObjectArray: ...
    def __setitem__(self, key: Any, value: Any) -> None: ...
    def __delitem__(self, key: Any) -> NoReturn: ...
    def __iter__(self) -> Iterator[Any]: ...
    def __len__(self) -> int: ...
    def __contains__(self, item: Any) -> bool: ...
