"""Handler for fix_keyboard command.

Windows: releases stuck modifier keys (Alt, Ctrl, Shift, Win) and unlocks
the foreground window lock — recovery for when keybd_event/SendKeys leaves
keys held at the OS level after KiCad UI automation.

macOS: no-op. Stuck modifier keys aren't a problem on macOS because we don't
use SendKeys-style automation against KiCad windows (UI scripting requires
Accessibility permission, which we don't request).
"""

import ctypes
import ctypes.wintypes
import sys

IS_WINDOWS = sys.platform == "win32"

if IS_WINDOWS:
    user32 = ctypes.windll.user32
else:
    user32 = None

# Key-up flag
KEYEVENTF_KEYUP = 0x0002

# Virtual key codes for all modifier keys
_MODIFIER_KEYS = [
    0x12,   # VK_MENU (Alt generic)
    0xA4,   # VK_LMENU (Left Alt)
    0xA5,   # VK_RMENU (Right Alt)
    0x11,   # VK_CONTROL (Ctrl generic)
    0xA2,   # VK_LCONTROL (Left Ctrl)
    0xA3,   # VK_RCONTROL (Right Ctrl)
    0x10,   # VK_SHIFT (Shift generic)
    0xA0,   # VK_LSHIFT (Left Shift)
    0xA1,   # VK_RSHIFT (Right Shift)
    0x5B,   # VK_LWIN (Left Win)
    0x5C,   # VK_RWIN (Right Win)
]

# SystemParametersInfo constants
SPI_SETFOREGROUNDLOCKTIMEOUT = 0x2001
SPIF_UPDATEINIFILE = 0x01
SPIF_SENDCHANGE = 0x02


def _get_stuck_keys() -> list[str]:
    """Check which modifier keys are currently pressed/stuck."""
    stuck = []
    names = {
        0x12: "Alt", 0x11: "Ctrl", 0x10: "Shift", 0x5B: "LWin", 0x5C: "RWin",
    }
    for vk, name in names.items():
        state = user32.GetAsyncKeyState(vk)
        if state & 0x8000:
            stuck.append(name)
    return stuck


def handle_fix_keyboard(kicad_info: dict, args: dict) -> dict:
    """Release all stuck modifier keys and unlock foreground window focus.

    Windows-only recovery for keybd_event/SendKeys leaving modifiers stuck.
    On macOS this returns a no-op success since we don't have the same problem.
    """
    if not IS_WINDOWS:
        return {
            "success": True,
            "output": "fix_keyboard is a Windows-only recovery command (no-op on this platform).",
        }

    # 1. Check which keys are stuck before fix
    stuck_before = _get_stuck_keys()

    # 2. Release all modifier keys (10 rounds for reliability)
    for _ in range(10):
        for vk in _MODIFIER_KEYS:
            user32.keybd_event(vk, 0, KEYEVENTF_KEYUP, 0)

    # 3. Unlock foreground window lock (LSFW_UNLOCK = 2)
    user32.LockSetForegroundWindow(2)

    # 4. Reset foreground lock timeout to 0 (allow any app to take foreground)
    user32.SystemParametersInfoW(
        SPI_SETFOREGROUNDLOCKTIMEOUT, 0, None,
        SPIF_UPDATEINIFILE | SPIF_SENDCHANGE,
    )

    # 5. Verify
    stuck_after = _get_stuck_keys()

    if stuck_before:
        detail = f"Stuck keys detected: {', '.join(stuck_before)}. "
    else:
        detail = "No stuck keys detected via GetAsyncKeyState. "

    if stuck_after:
        detail += f"WARNING: Keys still stuck after fix: {', '.join(stuck_after)}. "
        detail += "User may need to sign out and back in."
        return {
            "success": True,
            "output": detail + " Modifier keys released, foreground lock cleared.",
        }
    else:
        detail += "All modifier keys released successfully."
        return {
            "success": True,
            "output": detail + " Foreground lock cleared.",
        }