import abc
from collections.abc import Iterable, Iterator
from typing import TypeVar
from typing_extensions import TypeAlias

from .version import Version

# These exist at runtime, hence the public names
UnparsedVersion: TypeAlias = Version | str
UnparsedVersionVar = TypeVar("UnparsedVersionVar", bound=UnparsedVersion)  # noqa: Y001

class InvalidSpecifier(ValueError): ...

class BaseSpecifier(metaclass=abc.ABCMeta):
    @abc.abstractmethod
    def __str__(self) -> str: ...
    @abc.abstractmethod
    def __hash__(self) -> int: ...
    @abc.abstractmethod
    def __eq__(self, other: object) -> bool: ...
    @property
    @abc.abstractmethod
    def prereleases(self) -> bool | None: ...
    @prereleases.setter
    def prereleases(self, value: bool) -> None: ...
    @abc.abstractmethod
    def contains(self, item: str, prereleases: bool | None = None) -> bool: ...
    @abc.abstractmethod
    def filter(self, iterable: Iterable[UnparsedVersionVar], prereleases: bool | None = None) -> Iterator[UnparsedVersionVar]: ...

class Specifier(BaseSpecifier):
    def __init__(self, spec: str = "", prereleases: bool | None = None) -> None: ...
    @property  # type: ignore[override]
    def prereleases(self) -> bool: ...
    @prereleases.setter
    def prereleases(self, value: bool) -> None: ...
    @property
    def operator(self) -> str: ...
    @property
    def version(self) -> str: ...
    def __str__(self) -> str: ...  # noqa: Y029  # needed as it's abstract on the superclass
    def __hash__(self) -> int: ...
    def __eq__(self, other: object) -> bool: ...
    def __contains__(self, item: Version | str) -> bool: ...
    def contains(self, item: UnparsedVersion, prereleases: bool | None = None) -> bool: ...
    def filter(self, iterable: Iterable[UnparsedVersionVar], prereleases: bool | None = None) -> Iterator[UnparsedVersionVar]: ...

class SpecifierSet(BaseSpecifier):
    def __init__(self, spec: str = "", prereleases: bool | None = None) -> None: ...
    @property
    def prereleases(self) -> bool | None: ...
    @prereleases.setter
    def prereleases(self, value: bool) -> None: ...
    @property
    def operator(self) -> str: ...
    @property
    def version(self) -> str: ...
    def __str__(self) -> str: ...  # noqa: Y029  # needed as it's abstract on the superclass
    def __hash__(self) -> int: ...
    def __and__(self, other: SpecifierSet | str) -> SpecifierSet: ...
    def __len__(self) -> int: ...
    def __iter__(self) -> Iterator[Specifier]: ...
    def __eq__(self, other: object) -> bool: ...
    def __contains__(self, item: UnparsedVersion) -> bool: ...
    def contains(self, item: UnparsedVersion, prereleases: bool | None = None, installed: bool | None = None) -> bool: ...
    def filter(self, iterable: Iterable[UnparsedVersionVar], prereleases: bool | None = None) -> Iterator[UnparsedVersionVar]: ...
