from collections.abc import Callable, Iterator
from contextlib import contextmanager
from signal import Handlers
from signal import Signals as SignalEnum
from typing import Any

from typing_extensions import Self

__all__ = (
    "EX_FAILURE",
    "EX_OK",
    "EX_UNAVAILABLE",
    "EX_USAGE",
    "IS_WINDOWS",
    "SIGMAP",
    "SYSTEM",
    "DaemonContext",
    "IS_macOS",
    "LockFailed",
    "Pidfile",
    "close_open_fds",
    "create_pidlock",
    "detached",
    "fd_by_path",
    "get_errno_name",
    "get_fdmax",
    "ignore_errno",
    "initgroups",
    "isatty",
    "maybe_drop_privileges",
    "parse_gid",
    "parse_uid",
    "pyimplementation",
    "set_mp_process_title",
    "set_process_title",
    "setgid",
    "setgroups",
    "setuid",
    "signal_name",
    "signals",
)

DAEMON_WORKDIR: str
EX_OK: int
EX_FAILURE: int
EX_UNAVAILABLE: int
EX_USAGE: int
SYSTEM: str
IS_macOS: bool
IS_WINDOWS: bool
SIGMAP: dict[int, str]

class Signals:
    default: Handlers
    ignored: Handlers
    def arm_alarm(self, seconds: float) -> None: ...
    def ignore(self, *signals: int) -> None: ...
    def reset(self, sig: int) -> None: ...
    def reset_alarm(self) -> None: ...
    def signum(self, name: int | str) -> int: ...
    def supported(self, name: int | str) -> bool: ...
    def update(
        self,
        _d_: dict[int | SignalEnum, Callable[[int, Any], None]] | None = None,
        **sigmap: Callable[[int, Any], None],
    ) -> None: ...
    def __getitem__(self, name: int | str) -> Callable[[int, Any], None] | None: ...
    def __setitem__(
        self, name: int | str, handler: Callable[[int, Any], None]
    ) -> None: ...

signals: Signals

def pyimplementation() -> str: ...
def signal_name(signum: int) -> str | None: ...
def get_errno_name(n: int) -> str: ...
def get_fdmax(default: int | None = None) -> int: ...
def close_open_fds(keep: set[int] | None = None) -> None: ...
def fd_by_path(paths: list[str]) -> list[int]: ...
@contextmanager
def ignore_errno(*errnos: int) -> Iterator[None]: ...
def set_process_title(progname: str, info: str | None = None) -> None: ...
def set_mp_process_title(
    progname: str, info: str | None = None, hostname: str | None = None
) -> None: ...
def maybe_drop_privileges(
    uid: int | str | None = None, gid: int | str | None = None
) -> None: ...
def setgroups(groups: list[int]) -> None: ...
def initgroups(uid: int, gid: int) -> None: ...
def setgid(gid: int | str) -> None: ...
def setuid(uid: int | str) -> None: ...
def parse_uid(uid: int | str) -> int: ...
def parse_gid(gid: int | str) -> int: ...
def isatty(fh: Any) -> bool: ...
def detached(
    logfile: str | None = None,
    pidfile: str | None = None,
    uid: int | str | None = None,
    gid: int | str | None = None,
    umask: int = 0,
    workdir: str | None = None,
    fake: bool = False,
    **opts: Any,
) -> Any: ...
def create_pidlock(pidfile: str) -> Any: ...

class DaemonContext:
    open_fds: set[int] | None
    pidfile: str | None
    workdir: str
    umask: int | None

    def __init__(
        self,
        pidfile: str | None = None,
        workdir: str | None = None,
        umask: int | None = None,
        fake: bool = False,
        after_chdir: Callable[[], None] | None = None,
        after_forkers: bool = True,
        **kwargs: Any,
    ) -> None: ...
    def open(self) -> DaemonContext: ...
    def close(self, *args: Any) -> None: ...
    def redirect_to_null(self, fd: int) -> None: ...
    def __enter__(self) -> Self: ...
    def __exit__(self, *exc_info: object) -> None: ...

class Pidfile:
    path: str | None
    def __init__(self, path: str) -> None: ...
    def acquire(self) -> Pidfile: ...
    def is_locked(self) -> bool: ...
    def release(self, *args: Any) -> None: ...
    def read_pid(self) -> int | None: ...
    def remove(self) -> None: ...
    def remove_if_stale(self) -> bool: ...
    def write_pid(self) -> None: ...
    def __enter__(self) -> Self: ...
    def __exit__(self, *exc_info: object) -> None: ...

class LockFailed(Exception): ...
