from typing import TYPE_CHECKING, overload, Generic, TypeVar

if TYPE_CHECKING:
    from typing import Iterable, Callable, Literal, Type

    from re import Pattern

    from shinqlx import (
        Plugin,
        Player,
        Command,
        AbstractChannel,
        StatsData,
        GameStartData,
        GameEndData,
        RoundEndData,
        KillData,
        DeathData,
        UserinfoEventInput,
    )

_re_vote: Pattern

E = TypeVar("E", bound=EventDispatcher)

class EventDispatcher(Generic[E]):
    name: str
    plugins: dict[
        Plugin,
        tuple[
            Iterable[Callable],
            Iterable[Callable],
            Iterable[Callable],
            Iterable[Callable],
            Iterable[Callable],
        ],
    ]
    _args: Iterable[str] | None
    _return_value: str | bool | Iterable | None
    no_debug: Iterable[str]
    need_zmq_stats_enabled: bool

    def __init__(self) -> None: ...
    @overload
    def dispatch(self: EventDispatcher[ConsolePrintDispatcher], text: str) -> str | bool: ...
    @overload
    def dispatch(self: EventDispatcher[CommandDispatcher], caller: Player, command: Command, args: str) -> None: ...
    @overload
    def dispatch(self: EventDispatcher[ClientCommandDispatcher], player: Player, cmd: str) -> str | bool: ...
    @overload
    def dispatch(self: EventDispatcher[ServerCommandDispatcher], player: Player | None, cmd: str) -> str | bool: ...
    @overload
    def dispatch(self: EventDispatcher[FrameEventDispatcher]) -> bool: ...
    @overload
    def dispatch(self: EventDispatcher[SetConfigstringDispatcher], index: int, value: str) -> str | bool: ...
    @overload
    def dispatch(
        self: EventDispatcher[ChatEventDispatcher], player: Player, msg: str, channel: AbstractChannel
    ) -> str | bool: ...
    @overload
    def dispatch(self: EventDispatcher[UnloadDispatcher], plugin: Plugin | str) -> None: ...
    @overload
    def dispatch(self: EventDispatcher[PlayerConnectDispatcher], player: Player) -> str | bool: ...
    @overload
    def dispatch(self: EventDispatcher[PlayerLoadedDispatcher], player: Player) -> bool: ...
    @overload
    def dispatch(self: EventDispatcher[PlayerDisconnectDispatcher], player: Player, reason: str | None) -> bool: ...
    @overload
    def dispatch(self: EventDispatcher[PlayerSpawnDispatcher], player: Player) -> bool: ...
    @overload
    def dispatch(self: EventDispatcher[StatsDispatcher], stats: StatsData) -> bool: ...
    @overload
    def dispatch(self: EventDispatcher[VoteCalledDispatcher], player: Player, vote: str, args: str | None) -> bool: ...
    @overload
    def dispatch(self: EventDispatcher[VoteStartedDispatcher], vote: str, args: str | None) -> bool: ...
    @overload
    def dispatch(self: EventDispatcher[VoteEndedDispatcher], passed: bool) -> None: ...
    @overload
    def dispatch(self: EventDispatcher[VoteDispatcher], player: Player, yes: bool) -> bool: ...
    @overload
    def dispatch(self: EventDispatcher[GameCountdownDispatcher]) -> bool: ...
    @overload
    def dispatch(self: EventDispatcher[GameStartDispatcher], data: GameStartData) -> bool: ...
    @overload
    def dispatch(self: EventDispatcher[GameEndDispatcher], data: GameEndData) -> bool: ...
    @overload
    def dispatch(self: EventDispatcher[RoundCountdownDispatcher], round_number: int) -> bool: ...
    @overload
    def dispatch(self: EventDispatcher[RoundStartDispatcher], round_number: int) -> bool: ...
    @overload
    def dispatch(self: EventDispatcher[RoundEndDispatcher], data: RoundEndData) -> bool: ...
    @overload
    def dispatch(self: EventDispatcher[TeamSwitchDispatcher], player: Player, old_team: str, new_team: str) -> bool: ...
    @overload
    def dispatch(
        self: EventDispatcher[TeamSwitchAttemptDispatcher], player: Player, old_team: str, new_team: str
    ) -> bool: ...
    @overload
    def dispatch(self: EventDispatcher[MapDispatcher], mapname: str, factory: str) -> bool: ...
    @overload
    def dispatch(self: EventDispatcher[NewGameDispatcher]) -> bool: ...
    @overload
    def dispatch(self: EventDispatcher[KillDispatcher], victim: Player, killer: Player, data: KillData) -> bool: ...
    @overload
    def dispatch(
        self: EventDispatcher[DeathDispatcher], victim: Player, killer: Player | None, data: DeathData
    ) -> bool: ...
    @overload
    def dispatch(
        self: EventDispatcher[UserinfoDispatcher], player: Player, changed: UserinfoEventInput
    ) -> bool | UserinfoEventInput: ...
    @overload
    def dispatch(self: EventDispatcher[KamikazeUseDispatcher], player: Player) -> bool: ...
    @overload
    def dispatch(self: EventDispatcher[KamikazeExplodeDispatcher], player: Player, is_used_on_demand: bool) -> bool: ...
    @overload
    def dispatch(
        self: EventDispatcher[DamageDispatcher],
        target: Player | int | None,
        attacker: Player | int | None,
        damage: int,
        dflags: int,
        means_of_death: int,
    ) -> bool: ...
    def dispatch(self, *args, **kwargs) -> str | bool | Iterable | None: ...  # type: ignore
    def add_hook(self, plugin: str, handler: Callable, priority: int = ...) -> None: ...
    def remove_hook(self, plugin: str, handler: Callable, priority: int = ...) -> None: ...

class ConsolePrintDispatcher(EventDispatcher[ConsolePrintDispatcher]): ...
class CommandDispatcher(EventDispatcher[CommandDispatcher]): ...
class ClientCommandDispatcher(EventDispatcher[ClientCommandDispatcher]): ...
class ServerCommandDispatcher(EventDispatcher[ServerCommandDispatcher]): ...
class FrameEventDispatcher(EventDispatcher[FrameEventDispatcher]): ...
class SetConfigstringDispatcher(EventDispatcher[SetConfigstringDispatcher]): ...
class ChatEventDispatcher(EventDispatcher[ChatEventDispatcher]): ...
class UnloadDispatcher(EventDispatcher[UnloadDispatcher]): ...
class PlayerConnectDispatcher(EventDispatcher[PlayerConnectDispatcher]): ...
class PlayerLoadedDispatcher(EventDispatcher[PlayerLoadedDispatcher]): ...
class PlayerDisconnectDispatcher(EventDispatcher[PlayerDisconnectDispatcher]): ...
class PlayerSpawnDispatcher(EventDispatcher[PlayerSpawnDispatcher]): ...
class StatsDispatcher(EventDispatcher[StatsDispatcher]): ...
class VoteCalledDispatcher(EventDispatcher[VoteCalledDispatcher]): ...

class VoteStartedDispatcher(EventDispatcher[VoteStartedDispatcher]):
    _caller: Player | None

    def __init__(self) -> None: ...
    def caller(self, player: Player | None) -> None: ...

class VoteEndedDispatcher(EventDispatcher[VoteEndedDispatcher]): ...
class VoteDispatcher(EventDispatcher[VoteDispatcher]): ...
class GameCountdownDispatcher(EventDispatcher[GameCountdownDispatcher]): ...
class GameStartDispatcher(EventDispatcher[GameStartDispatcher]): ...
class GameEndDispatcher(EventDispatcher[GameEndDispatcher]): ...
class RoundCountdownDispatcher(EventDispatcher[RoundCountdownDispatcher]): ...
class RoundStartDispatcher(EventDispatcher[RoundStartDispatcher]): ...
class RoundEndDispatcher(EventDispatcher[RoundEndDispatcher]): ...
class TeamSwitchDispatcher(EventDispatcher[TeamSwitchDispatcher]): ...
class TeamSwitchAttemptDispatcher(EventDispatcher[TeamSwitchAttemptDispatcher]): ...
class MapDispatcher(EventDispatcher[MapDispatcher]): ...
class NewGameDispatcher(EventDispatcher[NewGameDispatcher]): ...
class KillDispatcher(EventDispatcher[KillDispatcher]): ...
class DeathDispatcher(EventDispatcher[DeathDispatcher]): ...
class UserinfoDispatcher(EventDispatcher[UserinfoDispatcher]): ...
class KamikazeUseDispatcher(EventDispatcher[KamikazeUseDispatcher]): ...
class KamikazeExplodeDispatcher(EventDispatcher[KamikazeExplodeDispatcher]): ...
class DamageDispatcher(EventDispatcher[DamageDispatcher]): ...

class EventDispatcherManager:
    def __init__(self) -> None: ...
    @overload
    def __getitem__(self, key: Literal["console_print"]) -> ConsolePrintDispatcher: ...
    @overload
    def __getitem__(self, key: Literal["command"]) -> CommandDispatcher: ...
    @overload
    def __getitem__(self, key: Literal["client_command"]) -> ClientCommandDispatcher: ...
    @overload
    def __getitem__(self, key: Literal["server_command"]) -> ServerCommandDispatcher: ...
    @overload
    def __getitem__(self, key: Literal["frame"]) -> FrameEventDispatcher: ...
    @overload
    def __getitem__(self, key: Literal["set_configstring"]) -> SetConfigstringDispatcher: ...
    @overload
    def __getitem__(self, key: Literal["chat"]) -> ChatEventDispatcher: ...
    @overload
    def __getitem__(self, key: Literal["unload"]) -> UnloadDispatcher: ...
    @overload
    def __getitem__(self, key: Literal["player_connect"]) -> PlayerConnectDispatcher: ...
    @overload
    def __getitem__(self, key: Literal["player_loaded"]) -> PlayerLoadedDispatcher: ...
    @overload
    def __getitem__(self, key: Literal["player_disconnect"]) -> PlayerDisconnectDispatcher: ...
    @overload
    def __getitem__(self, key: Literal["player_spawn"]) -> PlayerSpawnDispatcher: ...
    @overload
    def __getitem__(self, key: Literal["stats"]) -> StatsDispatcher: ...
    @overload
    def __getitem__(self, key: Literal["vote_called"]) -> VoteCalledDispatcher: ...
    @overload
    def __getitem__(self, key: Literal["vote_started"]) -> VoteStartedDispatcher: ...
    @overload
    def __getitem__(self, key: Literal["vote_ended"]) -> VoteEndedDispatcher: ...
    @overload
    def __getitem__(self, key: Literal["vote"]) -> VoteDispatcher: ...
    @overload
    def __getitem__(self, key: Literal["game_countdown"]) -> GameCountdownDispatcher: ...
    @overload
    def __getitem__(self, key: Literal["game_start"]) -> GameStartDispatcher: ...
    @overload
    def __getitem__(self, key: Literal["game_end"]) -> GameEndDispatcher: ...
    @overload
    def __getitem__(self, key: Literal["round_countdown"]) -> RoundCountdownDispatcher: ...
    @overload
    def __getitem__(self, key: Literal["round_start"]) -> RoundStartDispatcher: ...
    @overload
    def __getitem__(self, key: Literal["round_end"]) -> RoundEndDispatcher: ...
    @overload
    def __getitem__(self, key: Literal["team_switch"]) -> TeamSwitchDispatcher: ...
    @overload
    def __getitem__(self, key: Literal["team_switch_attempt"]) -> TeamSwitchAttemptDispatcher: ...
    @overload
    def __getitem__(self, key: Literal["map"]) -> MapDispatcher: ...
    @overload
    def __getitem__(self, key: Literal["new_game"]) -> NewGameDispatcher: ...
    @overload
    def __getitem__(self, key: Literal["kill"]) -> KillDispatcher: ...
    @overload
    def __getitem__(self, key: Literal["death"]) -> DeathDispatcher: ...
    @overload
    def __getitem__(self, key: Literal["userinfo"]) -> UserinfoDispatcher: ...
    @overload
    def __getitem__(self, key: Literal["kamikaze_use"]) -> KamikazeUseDispatcher: ...
    @overload
    def __getitem__(self, key: Literal["kamikaze_explode"]) -> KamikazeExplodeDispatcher: ...
    @overload
    def __getitem__(self, key: Literal["damage"]) -> DamageDispatcher: ...
    def __contains__(self, key: str) -> bool: ...
    def add_dispatcher(self, dispatcher: Type[EventDispatcher]) -> None: ...
    def remove_dispatcher(self, dispatcher: Type[EventDispatcher]) -> None: ...
    def remove_dispatcher_by_name(self, event_name: str) -> None: ...

EVENT_DISPATCHERS: EventDispatcherManager
