import sys
from collections.abc import Callable, Iterable
from ctypes import c_long
from typing import SupportsInt, TypeVar
from typing_extensions import Literal, TypeAlias

from ._generic import GenericListener as _GenericListener
from ._mouse_event import (
    DOUBLE as DOUBLE,
    DOWN as DOWN,
    LEFT as LEFT,
    MIDDLE as MIDDLE,
    RIGHT as RIGHT,
    UP as UP,
    X2 as X2,
    ButtonEvent as ButtonEvent,
    MoveEvent as MoveEvent,
    WheelEvent as WheelEvent,
    X as X,
    _MouseButton,
    _MouseEvent,
    _MouseEventType,
)

# mypy doesn't support PEP 646's TypeVarTuple yet: https://github.com/python/mypy/issues/12280
# _Ts = TypeVarTuple("_Ts")
_Ts: TypeAlias = tuple[object, ...]
_Callback: TypeAlias = Callable[[_MouseEvent], bool | None]
_C = TypeVar("_C", bound=_Callback)

class _MouseListener(_GenericListener):
    def init(self) -> None: ...
    def pre_process_event(  # type: ignore[override]  # Mouse specific events and return
        self, event: _MouseEvent
    ) -> Literal[True]: ...
    def listen(self) -> None: ...

def is_pressed(button: _MouseButton = ...) -> bool: ...
def press(button: _MouseButton = ...) -> None: ...
def release(button: _MouseButton = ...) -> None: ...
def click(button: _MouseButton = ...) -> None: ...
def double_click(button: _MouseButton = ...) -> None: ...
def right_click() -> None: ...
def wheel(delta: int = ...) -> None: ...
def move(x: SupportsInt, y: SupportsInt, absolute: bool = ..., duration: float = ...) -> None: ...
def drag(start_x: int, start_y: int, end_x: int, end_y: int, absolute: bool = ..., duration: float = ...) -> None: ...
def on_button(
    callback: Callable[..., None],
    args: _Ts = ...,
    buttons: list[_MouseButton] | tuple[_MouseButton, ...] | _MouseButton = ...,
    types: list[_MouseEventType] | tuple[_MouseEventType, ...] | _MouseEventType = ...,
) -> _Callback: ...
def on_click(callback: Callable[..., None], args: _Ts = ...) -> _Callback: ...
def on_double_click(callback: Callable[..., None], args: _Ts = ...) -> _Callback: ...
def on_right_click(callback: Callable[..., None], args: _Ts = ...) -> _Callback: ...
def on_middle_click(callback: Callable[..., None], args: _Ts = ...) -> _Callback: ...
def wait(button: _MouseButton = ..., target_types: tuple[_MouseEventType] = ...) -> None: ...

if sys.platform == "win32":
    def get_position() -> tuple[c_long, c_long]: ...

else:
    def get_position() -> tuple[int, int]: ...

def hook(callback: _C) -> _C: ...
def unhook(callback: _Callback) -> None: ...
def unhook_all() -> None: ...
def record(button: _MouseButton = ..., target_types: tuple[_MouseEventType] = ...) -> _MouseEvent: ...
def play(
    events: Iterable[_MouseEvent],
    speed_factor: float = ...,
    include_clicks: bool = ...,
    include_moves: bool = ...,
    include_wheel: bool = ...,
) -> None: ...

replay = play
hold = press
