from _typeshed import SupportsKeysAndGetItem
from collections.abc import Generator, ItemsView, Iterable, Iterator, KeysView, ValuesView
from typing import Any, Generic, NoReturn, TypeAlias, TypeVar, overload
from typing_extensions import Self

_KT = TypeVar("_KT")
_VT = TypeVar("_VT")
_T = TypeVar("_T")

class OrderedMultiDict(dict[_KT, _VT]):
    def add(self, k: _KT, v: _VT) -> None: ...
    def addlist(self, k: _KT, v: Iterable[_VT]) -> None: ...
    def clear(self) -> None: ...
    def copy(self) -> Self: ...
    def counts(self) -> OrderedMultiDict[_KT, int]: ...

    @overload  # type: ignore[override]
    @classmethod
    def fromkeys(cls, keys: Iterable[_KT], default: None = None) -> OrderedMultiDict[_KT, Any | None]: ...
    @overload
    @classmethod
    def fromkeys(cls, keys: Iterable[_KT], default: _T) -> OrderedMultiDict[_KT, _T]: ...

    @overload  # type: ignore[override]
    def get(self, k: _KT, default: None = None) -> _VT | None: ...
    @overload
    def get(self, k: _KT, default: _VT) -> _VT: ...

    @overload
    def getlist(self, k: _KT) -> list[_VT]: ...
    @overload
    def getlist(self, k: _KT, default: _T) -> list[_VT] | _T: ...

    def inverted(self) -> OrderedMultiDict[_VT, _KT]: ...
    def items(self, multi: bool = False) -> list[tuple[_KT, _VT]]: ...  # type: ignore[override]
    def iteritems(self, multi: bool = False) -> Generator[tuple[_KT, _VT]]: ...
    def iterkeys(self, multi: bool = False) -> Generator[_KT]: ...
    def itervalues(self, multi: bool = False) -> Generator[_VT]: ...
    def keys(self, multi: bool = False) -> list[_KT]: ...  # type: ignore[override]
    def pop(self, k: _KT, default: _VT = ...) -> _VT: ...  # type: ignore[override]
    def popall(self, k: _KT, default: _VT = ...) -> list[_VT]: ...
    def poplast(self, k: _KT = ..., default: _VT = ...) -> _VT: ...

    @overload  # type: ignore[override]
    def setdefault(self, k: _KT, default: None = None) -> _VT | None: ...
    @overload
    def setdefault(self, k: _KT, default: _VT) -> _VT: ...

    def sorted(self, key: _KT | None = None, reverse: bool = False) -> Self: ...
    def sortedvalues(self, key: _KT | None = None, reverse: bool = False) -> Self: ...
    def todict(self, multi: bool = False) -> dict[_KT, _VT]: ...
    def update(self, E: SupportsKeysAndGetItem[_KT, _VT] | Iterable[tuple[_KT, _VT]], **F) -> None: ...  # type: ignore[override]
    def update_extend(self, E: SupportsKeysAndGetItem[_KT, _VT] | Iterable[tuple[_KT, _VT]], **F) -> None: ...
    def values(self, multi: bool = False) -> list[_VT]: ...  # type: ignore[override]
    def viewitems(self) -> ItemsView[_KT, _VT]: ...
    def viewkeys(self) -> KeysView[_KT]: ...
    def viewvalues(self) -> ValuesView[_VT]: ...

OMD: TypeAlias = OrderedMultiDict[_KT, _VT]
MultiDict: TypeAlias = OrderedMultiDict[_KT, _VT]

class FastIterOrderedMultiDict(OrderedMultiDict[_KT, _VT]):  # undocumented
    def iteritems(self, multi: bool = False) -> Generator[tuple[_KT, _VT]]: ...
    def iterkeys(self, multi: bool = False) -> Generator[_KT]: ...

class OneToOne(dict[_KT, _VT]):
    __slots__ = ("inv",)
    inv: OneToOne[_VT, _KT]
    def clear(self) -> None: ...
    def copy(self) -> Self: ...
    def pop(self, key: _KT, default: _VT | _T = ...) -> _VT | _T: ...
    def popitem(self) -> tuple[_KT, _VT]: ...

    @overload
    def setdefault(self, key: _KT, default: None = None) -> _VT | None: ...
    @overload
    def setdefault(self, key: _KT, default: _VT) -> _VT: ...

    @classmethod
    def unique(cls, *a, **kw) -> Self: ...
    def update(self, dict_or_iterable, **kw) -> None: ...  # type: ignore[override]

class ManyToMany(Generic[_KT, _VT]):
    data: dict[_KT, set[_VT]]
    inv: ManyToMany[_VT, _KT]
    def __contains__(self, key: object) -> bool: ...
    def __delitem__(self, key: _KT) -> None: ...
    def __eq__(self, other): ...
    def __getitem__(self, key: _KT) -> frozenset[_VT]: ...
    def __init__(
        self, items: ManyToMany[_KT, _VT] | SupportsKeysAndGetItem[_KT, _VT] | Iterable[tuple[_KT, _VT]] | None = None
    ) -> None: ...
    def __iter__(self) -> Iterator[_KT]: ...
    def __len__(self) -> int: ...
    def __setitem__(self, key: _KT, vals: Iterable[_VT]) -> None: ...
    def add(self, key: _KT, val: _VT) -> None: ...

    @overload
    def get(self, key: _KT) -> frozenset[_VT]: ...
    @overload
    def get(self, key: _KT, default: _T) -> frozenset[_VT] | _T: ...

    def iteritems(self) -> Generator[tuple[_KT, _VT]]: ...
    def keys(self) -> KeysView[_KT]: ...
    def remove(self, key: _KT, val: _VT) -> None: ...
    def replace(self, key: _KT, newkey: _KT) -> None: ...
    def update(self, iterable: ManyToMany[_KT, _VT] | SupportsKeysAndGetItem[_KT, _VT] | Iterable[tuple[_KT, _VT]]) -> None: ...

def subdict(d: dict[_KT, _VT], keep: Iterable[_KT] | None = None, drop: Iterable[_KT] | None = None) -> dict[_KT, _VT]: ...

class FrozenHashError(TypeError): ...  # undocumented

class FrozenDict(dict[_KT, _VT]):
    __slots__ = ("_hash",)
    def __copy__(self) -> Self: ...
    @classmethod
    def fromkeys(cls, keys: Iterable[_KT], value: _VT | None = None) -> Self: ...  # type: ignore[override]
    def updated(self, *a, **kw) -> Self: ...
    def __ior__(self, *a, **kw) -> NoReturn: ...  # type: ignore[misc] # noqa: Y034 # Signature conflicts with superclass
    def __setitem__(self, *a, **kw) -> NoReturn: ...
    def __delitem__(self, *a, **kw) -> NoReturn: ...
    def update(self, *a, **kw) -> NoReturn: ...
    def pop(self, *a, **kw) -> NoReturn: ...
    def popitem(self, *a, **kw) -> NoReturn: ...
    def setdefault(self, *a, **kw) -> NoReturn: ...
    def clear(self, *a, **kw) -> NoReturn: ...

__all__ = ["MultiDict", "OMD", "OrderedMultiDict", "OneToOne", "ManyToMany", "subdict", "FrozenDict"]
