import sys
from _typeshed import AnyOrLiteralStr, BytesPath, FileDescriptorOrPath, StrOrBytesPath, StrPath
from collections.abc import Iterable
from genericpath import (
    ALLOW_MISSING as ALLOW_MISSING,
    _AllowMissingType,
    commonprefix as commonprefix,
    exists as exists,
    getatime as getatime,
    getctime as getctime,
    getmtime as getmtime,
    getsize as getsize,
    isdir as isdir,
    isfile as isfile,
    samefile as samefile,
    sameopenfile as sameopenfile,
    samestat as samestat,
)

if sys.version_info >= (3, 15):
    from genericpath import ALL_BUT_LAST as ALL_BUT_LAST

if sys.version_info >= (3, 13):
    from genericpath import isdevdrive as isdevdrive
from os import PathLike
from typing import AnyStr, overload
from typing_extensions import LiteralString

__all__ = [
    "normcase",
    "isabs",
    "join",
    "splitdrive",
    "split",
    "splitext",
    "basename",
    "dirname",
    "commonprefix",
    "getsize",
    "getmtime",
    "getatime",
    "getctime",
    "islink",
    "exists",
    "lexists",
    "isdir",
    "isfile",
    "ismount",
    "expanduser",
    "expandvars",
    "normpath",
    "abspath",
    "samefile",
    "sameopenfile",
    "samestat",
    "curdir",
    "pardir",
    "sep",
    "pathsep",
    "defpath",
    "altsep",
    "extsep",
    "devnull",
    "realpath",
    "supports_unicode_filenames",
    "relpath",
    "commonpath",
]
__all__ += ["ALLOW_MISSING"]
if sys.version_info >= (3, 15):
    __all__ += ["ALL_BUT_LAST"]
if sys.version_info >= (3, 12):
    __all__ += ["isjunction", "splitroot"]
if sys.version_info >= (3, 13):
    __all__ += ["isdevdrive"]

supports_unicode_filenames: bool
# aliases (also in os)
curdir: LiteralString
pardir: LiteralString
sep: LiteralString
altsep: LiteralString | None
extsep: LiteralString
pathsep: LiteralString
defpath: LiteralString
devnull: LiteralString

# Overloads are necessary to work around python/mypy#17952 & python/mypy#11880
@overload
def abspath(path: PathLike[AnyStr]) -> AnyStr: ...
@overload
def abspath(path: AnyStr) -> AnyStr: ...

if sys.version_info >= (3, 15):
    @overload
    def basename(p: PathLike[AnyStr], /) -> AnyStr: ...
    @overload
    def basename(p: AnyOrLiteralStr, /) -> AnyOrLiteralStr: ...

    @overload
    def dirname(p: PathLike[AnyStr], /) -> AnyStr: ...
    @overload
    def dirname(p: AnyOrLiteralStr, /) -> AnyOrLiteralStr: ...
else:
    @overload
    def basename(p: PathLike[AnyStr]) -> AnyStr: ...
    @overload
    def basename(p: AnyOrLiteralStr) -> AnyOrLiteralStr: ...

    @overload
    def dirname(p: PathLike[AnyStr]) -> AnyStr: ...
    @overload
    def dirname(p: AnyOrLiteralStr) -> AnyOrLiteralStr: ...

@overload
def expanduser(path: PathLike[AnyStr]) -> AnyStr: ...
@overload
def expanduser(path: AnyStr) -> AnyStr: ...

@overload
def expandvars(path: PathLike[AnyStr]) -> AnyStr: ...
@overload
def expandvars(path: AnyStr) -> AnyStr: ...

if sys.version_info >= (3, 15):
    @overload
    def normcase(s: PathLike[AnyStr], /) -> AnyStr: ...
    @overload
    def normcase(s: AnyOrLiteralStr, /) -> AnyOrLiteralStr: ...
else:
    @overload
    def normcase(s: PathLike[AnyStr]) -> AnyStr: ...
    @overload
    def normcase(s: AnyOrLiteralStr) -> AnyOrLiteralStr: ...

@overload
def normpath(path: PathLike[AnyStr]) -> AnyStr:
    """Normalize path, eliminating double slashes, etc."""
    ...
@overload
def normpath(path: AnyOrLiteralStr) -> AnyOrLiteralStr:
    """Normalize path, eliminating double slashes, etc."""
    ...

@overload
def commonpath(paths: Iterable[LiteralString]) -> LiteralString: ...
@overload
def commonpath(paths: Iterable[StrPath]) -> str: ...
@overload
def commonpath(paths: Iterable[BytesPath]) -> bytes: ...

# First parameter is not actually pos-only before Python 3.15,
# but must be defined as pos-only in the stub or cross-platform code doesn't type-check,
# as the parameter name is different in ntpath.join()
@overload
def join(a: LiteralString, /, *paths: LiteralString) -> LiteralString: ...
@overload
def join(a: StrPath, /, *paths: StrPath) -> str: ...
@overload
def join(a: BytesPath, /, *paths: BytesPath) -> bytes: ...

if sys.version_info >= (3, 15):
    @overload
    def realpath(filename: PathLike[AnyStr], /, *, strict: bool | _AllowMissingType = False) -> AnyStr: ...
    @overload
    def realpath(filename: AnyStr, /, *, strict: bool | _AllowMissingType = False) -> AnyStr: ...
else:
    @overload
    def realpath(filename: PathLike[AnyStr], *, strict: bool | _AllowMissingType = False) -> AnyStr: ...
    @overload
    def realpath(filename: AnyStr, *, strict: bool | _AllowMissingType = False) -> AnyStr: ...

@overload
def relpath(path: LiteralString, start: LiteralString | None = None) -> LiteralString: ...
@overload
def relpath(path: BytesPath, start: BytesPath | None = None) -> bytes: ...
@overload
def relpath(path: StrPath, start: StrPath | None = None) -> str: ...

if sys.version_info >= (3, 15):
    @overload
    def split(p: PathLike[AnyStr], /) -> tuple[AnyStr, AnyStr]: ...
    @overload
    def split(p: AnyOrLiteralStr, /) -> tuple[AnyOrLiteralStr, AnyOrLiteralStr]: ...

    @overload
    def splitdrive(p: PathLike[AnyStr], /) -> tuple[AnyStr, AnyStr]: ...
    @overload
    def splitdrive(p: AnyOrLiteralStr, /) -> tuple[AnyOrLiteralStr, AnyOrLiteralStr]: ...
else:
    @overload
    def split(p: PathLike[AnyStr]) -> tuple[AnyStr, AnyStr]: ...
    @overload
    def split(p: AnyOrLiteralStr) -> tuple[AnyOrLiteralStr, AnyOrLiteralStr]: ...

    @overload
    def splitdrive(p: PathLike[AnyStr]) -> tuple[AnyStr, AnyStr]: ...
    @overload
    def splitdrive(p: AnyOrLiteralStr) -> tuple[AnyOrLiteralStr, AnyOrLiteralStr]: ...

if sys.version_info >= (3, 15):
    @overload
    def splitext(p: PathLike[AnyStr], /) -> tuple[AnyStr, AnyStr]: ...
    @overload
    def splitext(p: AnyOrLiteralStr, /) -> tuple[AnyOrLiteralStr, AnyOrLiteralStr]: ...
else:
    @overload
    def splitext(p: PathLike[AnyStr]) -> tuple[AnyStr, AnyStr]: ...
    @overload
    def splitext(p: AnyOrLiteralStr) -> tuple[AnyOrLiteralStr, AnyOrLiteralStr]: ...

if sys.version_info >= (3, 15):
    def isabs(s: StrOrBytesPath, /) -> bool: ...

else:
    def isabs(s: StrOrBytesPath) -> bool: ...

def islink(path: FileDescriptorOrPath) -> bool: ...
def ismount(path: FileDescriptorOrPath) -> bool: ...
def lexists(path: FileDescriptorOrPath) -> bool: ...

if sys.version_info >= (3, 12):
    def isjunction(path: StrOrBytesPath) -> bool: ...

    if sys.version_info >= (3, 15):
        @overload
        def splitroot(path: AnyOrLiteralStr, /) -> tuple[AnyOrLiteralStr, AnyOrLiteralStr, AnyOrLiteralStr]: ...
        @overload
        def splitroot(path: PathLike[AnyStr], /) -> tuple[AnyStr, AnyStr, AnyStr]: ...
    else:
        @overload
        def splitroot(p: AnyOrLiteralStr) -> tuple[AnyOrLiteralStr, AnyOrLiteralStr, AnyOrLiteralStr]:
            """
            Split a pathname into drive, root and tail.

            The tail contains anything after the root.
            """
            ...
        @overload
        def splitroot(p: PathLike[AnyStr]) -> tuple[AnyStr, AnyStr, AnyStr]:
            """
            Split a pathname into drive, root and tail.

            The tail contains anything after the root.
            """
            ...
