"""Dependency-free Windows global kill switch: Ctrl+Alt+Shift+Escape."""

from __future__ import annotations

import sys
import threading
from typing import Callable


class GlobalKillSwitch:
    HOTKEY = "Ctrl+Alt+Shift+Esc"
    _HOTKEY_ID = 0x4F4D
    _WM_HOTKEY = 0x0312
    _WM_QUIT = 0x0012
    _VK_ESCAPE = 0x1B
    _MOD_ALT = 0x0001
    _MOD_CONTROL = 0x0002
    _MOD_SHIFT = 0x0004
    _MOD_NOREPEAT = 0x4000

    def __init__(
        self,
        callback: Callable[[str], None],
        *,
        platform_name: str | None = None,
    ) -> None:
        self._callback = callback
        self._platform = sys.platform if platform_name is None else platform_name
        self._thread: threading.Thread | None = None
        self._thread_id: int | None = None
        self._ready = threading.Event()
        self._registered = False
        self._error: str | None = None

    @property
    def registered(self) -> bool:
        return self._registered

    @property
    def error(self) -> str | None:
        return self._error

    def start(self) -> bool:
        if self._platform != "win32":
            self._error = "global hotkey is available on Windows only"
            return False
        if self._thread and self._thread.is_alive():
            return self._registered
        self._ready.clear()
        self._thread = threading.Thread(target=self._run, name="omni-desktop-kill-switch", daemon=True)
        self._thread.start()
        self._ready.wait(timeout=2.0)
        return self._registered

    def stop(self) -> None:
        if self._thread_id is not None:
            try:
                import ctypes

                ctypes.windll.user32.PostThreadMessageW(self._thread_id, self._WM_QUIT, 0, 0)
            except Exception:
                pass
        thread = self._thread
        if thread and thread.is_alive() and thread is not threading.current_thread():
            thread.join(timeout=2.0)

    def _run(self) -> None:
        try:
            import ctypes
            from ctypes import wintypes

            user32 = ctypes.windll.user32
            kernel32 = ctypes.windll.kernel32
            self._thread_id = int(kernel32.GetCurrentThreadId())
            modifiers = self._MOD_ALT | self._MOD_CONTROL | self._MOD_SHIFT | self._MOD_NOREPEAT
            if not user32.RegisterHotKey(None, self._HOTKEY_ID, modifiers, self._VK_ESCAPE):
                self._error = "global kill-switch hotkey could not be registered"
                self._ready.set()
                return
            self._registered = True
            self._ready.set()
            message = wintypes.MSG()
            while user32.GetMessageW(ctypes.byref(message), None, 0, 0) > 0:
                if message.message == self._WM_HOTKEY and message.wParam == self._HOTKEY_ID:
                    try:
                        self._callback(self.HOTKEY)
                    except Exception:
                        pass
        except Exception as exc:
            self._error = f"kill switch unavailable: {type(exc).__name__}"
            self._ready.set()
        finally:
            if self._registered:
                try:
                    import ctypes

                    ctypes.windll.user32.UnregisterHotKey(None, self._HOTKEY_ID)
                except Exception:
                    pass
            self._registered = False
            self._ready.set()


class GlobalEscapeSwitch:
    """Best-effort global Esc hook used only to abort an active Overtake run."""

    HOTKEY = "Esc"
    _HOTKEY_ID = 0x4F4E
    _WM_HOTKEY = 0x0312
    _WM_QUIT = 0x0012
    _VK_ESCAPE = 0x1B

    def __init__(
        self,
        callback: Callable[[str], None],
        *,
        platform_name: str | None = None,
    ) -> None:
        self._callback = callback
        self._platform = sys.platform if platform_name is None else platform_name
        self._thread: threading.Thread | None = None
        self._thread_id: int | None = None
        self._ready = threading.Event()
        self._registered = False
        self._error: str | None = None

    @property
    def registered(self) -> bool:
        return self._registered

    @property
    def error(self) -> str | None:
        return self._error

    def start(self) -> bool:
        if self._platform != "win32":
            self._error = "global Esc hook is available on Windows only"
            return False
        if self._thread and self._thread.is_alive():
            return self._registered
        self._ready.clear()
        self._thread = threading.Thread(target=self._run, name="omni-overtake-escape", daemon=True)
        self._thread.start()
        self._ready.wait(timeout=2.0)
        return self._registered

    def stop(self) -> None:
        if self._thread_id is not None:
            try:
                import ctypes

                ctypes.windll.user32.PostThreadMessageW(self._thread_id, self._WM_QUIT, 0, 0)
            except Exception:
                pass
        thread = self._thread
        if thread and thread.is_alive() and thread is not threading.current_thread():
            thread.join(timeout=2.0)

    def _run(self) -> None:
        try:
            import ctypes
            from ctypes import wintypes

            user32 = ctypes.windll.user32
            kernel32 = ctypes.windll.kernel32
            self._thread_id = int(kernel32.GetCurrentThreadId())
            if not user32.RegisterHotKey(None, self._HOTKEY_ID, 0, self._VK_ESCAPE):
                self._error = "global Esc hook could not be registered"
                self._ready.set()
                return
            self._registered = True
            self._ready.set()
            message = wintypes.MSG()
            while user32.GetMessageW(ctypes.byref(message), None, 0, 0) > 0:
                if message.message == self._WM_HOTKEY and message.wParam == self._HOTKEY_ID:
                    try:
                        self._callback(self.HOTKEY)
                    except Exception:
                        pass
        except Exception as exc:
            self._error = f"global Esc hook unavailable: {type(exc).__name__}"
            self._ready.set()
        finally:
            if self._registered:
                try:
                    import ctypes

                    ctypes.windll.user32.UnregisterHotKey(None, self._HOTKEY_ID)
                except Exception:
                    pass
            self._registered = False
            self._ready.set()
