import sys
from typing import (
    Callable,
    Literal,
)

if sys.version_info >= (3, 11):
    from typing import Self
else:
    from typing_extensions import Self

from ..MPI import (
    COMM_SELF,
    INFO_NULL,
    Info,
    Intracomm,
)
from ..typing import T

__all__: list[str] = [
    "Sequential",
    "Counter",
    "Mutex",
    "Condition",
    "Semaphore",
]

class Sequential:
    comm: Intracomm
    tag: int
    def __init__(
        self,
        comm: Intracomm,
        tag: int = 0,
    ) -> None: ...
    def __enter__(self) -> Self: ...
    def __exit__(self, *exc: object) -> None: ...
    def begin(self) -> None: ...
    def end(self) -> None: ...

class Counter:
    def __init__(
        self,
        start: int = 0,
        step: int = 1,
        *,
        typecode: str = "i",
        comm: Intracomm = COMM_SELF,
        info: Info = INFO_NULL,
        root: int = 0,
    ) -> None: ...
    def __iter__(self) -> Self: ...
    def __next__(self) -> int: ...
    def next(self, incr: int | None = None) -> int: ...
    def free(self) -> None: ...

class Mutex:
    def __init__(
        self,
        *,
        recursive: bool = False,
        comm: Intracomm = COMM_SELF,
        info: Info = INFO_NULL,
    ) -> None: ...
    def __enter__(self) -> Self: ...
    def __exit__(self, *exc: object) -> None: ...
    def acquire(self, blocking: bool = True) -> bool: ...
    def release(self) -> None: ...
    def locked(self) -> bool: ...
    def count(self) -> int: ...
    def free(self) -> None: ...

class Condition:
    def __init__(
        self,
        mutex: Mutex | None = None,
        *,
        recursive: bool = True,
        comm: Intracomm = COMM_SELF,
        info: Info = INFO_NULL,
    ) -> None: ...
    def __enter__(self) -> Self: ...
    def __exit__(self, *exc: object) -> None: ...
    def acquire(self, blocking: bool = True) -> bool: ...
    def release(self) -> None: ...
    def locked(self) -> bool: ...
    def wait(self) -> Literal[True]: ...
    def wait_for(self, predicate: Callable[[], T]) -> T: ...
    def notify(self, n: int = 1) -> int: ...
    def notify_all(self) -> int: ...
    def free(self) -> None: ...

class Semaphore:
    def __init__(
        self,
        value: int = 1,
        *,
        bounded: bool = True,
        comm: Intracomm = COMM_SELF,
        info: Info = INFO_NULL,
    ) -> None: ...
    def __enter__(self) -> Self: ...
    def __exit__(self, *exc: object) -> None: ...
    def acquire(self, blocking: bool = True) -> bool: ...
    def release(self, n: int = 1) -> None: ...
    def free(self) -> None: ...
