"""Qt native event filter that owns a message-only HWND.

Receives ``WM_HOTKEY`` (global hotkey), ``WM_POWERBROADCAST`` (suspend /
resume), and ``WM_WTSSESSION_CHANGE`` (lock / unlock) and dispatches them
to a bound ``HotkeyService``.
"""
from __future__ import annotations

import ctypes
from ctypes import wintypes
from typing import TYPE_CHECKING

from loguru import logger
from PySide6.QtCore import QAbstractNativeEventFilter

from utils.win32_input import (
    PBT_APMRESUMEAUTOMATIC, PBT_APMRESUMESUSPEND, PBT_APMSUSPEND,
    WM_HOTKEY, WM_POWERBROADCAST, WM_WTSSESSION_CHANGE,
    WTS_SESSION_LOCK, WTS_SESSION_UNLOCK,
    create_message_only_window, destroy_window,
    register_session_notification, unregister_session_notification,
)

if TYPE_CHECKING:
    from services.hotkey_service import HotkeyService


class _MSG(ctypes.Structure):
    """Win32 MSG struct — mirrors the layout of ``PySide6`` native events."""
    _fields_ = [
        ("hwnd", wintypes.HWND),
        ("message", wintypes.UINT),
        ("wParam", wintypes.WPARAM),
        ("lParam", wintypes.LPARAM),
        ("time", wintypes.DWORD),
        ("pt_x", wintypes.LONG),
        ("pt_y", wintypes.LONG),
    ]


class HotkeyNativeEventFilter(QAbstractNativeEventFilter):
    """Own a message-only HWND and dispatch hotkey / power / session events."""

    def __init__(self) -> None:
        super().__init__()
        self._hwnd: int = 0
        self._service: HotkeyService | None = None
        self._session_registered = False

    # ─── lifecycle ───────────────────────────────────────────────────────
    def initialize(self) -> int:
        """Create the message-only HWND and register for session events.

        Must be called on the Qt main thread before installing the filter.
        Returns the HWND (0 on failure).
        """
        if self._hwnd:
            return self._hwnd

        hwnd = create_message_only_window()
        if not hwnd:
            logger.error("Failed to create message-only window for hotkeys")
            return 0

        self._hwnd = hwnd
        self._session_registered = register_session_notification(hwnd)
        if not self._session_registered:
            logger.warning(
                "WTSRegisterSessionNotification failed — "
                "lock/unlock events will be missed",
            )
        logger.debug("HotkeyNativeEventFilter initialized, hwnd={}", hwnd)
        return hwnd

    def shutdown(self) -> None:
        if self._session_registered and self._hwnd:
            try:
                unregister_session_notification(self._hwnd)
            except Exception as e:
                logger.warning("WTSUnRegisterSessionNotification error: {}", e)
            self._session_registered = False
        if self._hwnd:
            try:
                destroy_window(self._hwnd)
            except Exception as e:
                logger.warning("DestroyWindow error: {}", e)
            self._hwnd = 0

    @property
    def hwnd(self) -> int:
        return self._hwnd

    # ─── service binding ─────────────────────────────────────────────────
    def bind_service(self, service: HotkeyService) -> None:
        self._service = service

    # ─── Qt native event filter ──────────────────────────────────────────
    def nativeEventFilter(self, eventType, message):  # type: ignore[override]
        # Both generic (queued) and dispatcher (inline) messages reach us
        # on Windows — handle both defensively.
        if eventType not in (
            b"windows_generic_MSG", b"windows_dispatcher_MSG",
        ):
            return False, 0

        try:
            msg = _MSG.from_address(int(message))
        except Exception:
            return False, 0

        svc = self._service
        if svc is None:
            return False, 0

        try:
            if msg.message == WM_HOTKEY:
                svc.on_wm_hotkey(int(msg.wParam))
            elif msg.message == WM_POWERBROADCAST:
                w = int(msg.wParam)
                if w == PBT_APMSUSPEND:
                    svc.on_suspend()
                elif w in (PBT_APMRESUMESUSPEND, PBT_APMRESUMEAUTOMATIC):
                    svc.on_resume()
            elif msg.message == WM_WTSSESSION_CHANGE:
                w = int(msg.wParam)
                if w == WTS_SESSION_LOCK:
                    svc.on_session_lock()
                elif w == WTS_SESSION_UNLOCK:
                    svc.on_session_unlock()
        except Exception as e:
            logger.exception("HotkeyNativeEventFilter dispatch error: {}", e)

        # Never swallow OS messages — other filters must still see them.
        return False, 0
