"""Win32 window management via ctypes — find, position, and close windows."""

import ctypes
import ctypes.wintypes
import time

user32 = ctypes.windll.user32

# Make DPI-aware so coordinates match physical pixels (screenshots/highlights)
try:
    user32.SetProcessDPIAware()
except Exception:
    pass

# Constants
SW_RESTORE = 9
SW_SHOWNOACTIVATE = 4
SWP_NOZORDER = 0x0004
SWP_NOACTIVATE = 0x0010
WM_CLOSE = 0x0010
VK_MENU = 0x12  # Alt key
KEYEVENTF_KEYUP = 0x0002


def get_screen_size() -> tuple:
    """Return (width, height) of the primary monitor."""
    return user32.GetSystemMetrics(0), user32.GetSystemMetrics(1)


def find_windows_by_title(substring: str) -> list:
    """Find all visible windows containing substring in title.

    Returns list of (hwnd, title) tuples.
    """
    results = []

    def callback(hwnd, _lparam):
        if user32.IsWindowVisible(hwnd):
            length = user32.GetWindowTextLengthW(hwnd)
            if length > 0:
                buf = ctypes.create_unicode_buffer(length + 1)
                user32.GetWindowTextW(hwnd, buf, length + 1)
                if substring.lower() in buf.value.lower():
                    results.append((hwnd, buf.value))
        return True

    WNDENUMPROC = ctypes.WINFUNCTYPE(
        ctypes.c_bool, ctypes.wintypes.HWND, ctypes.wintypes.LPARAM
    )
    user32.EnumWindows(WNDENUMPROC(callback), 0)
    return results


def position_window(hwnd: int, x: int, y: int, w: int, h: int):
    """Move and resize a window."""
    user32.ShowWindow(hwnd, SW_RESTORE)
    user32.SetWindowPos(hwnd, 0, x, y, w, h, SWP_NOZORDER)


def bring_to_front(hwnd: int):
    """Bring a window to the foreground using the Alt-key trick."""
    # Press and release Alt to allow SetForegroundWindow from background
    user32.keybd_event(VK_MENU, 0, 0, 0)
    user32.keybd_event(VK_MENU, 0, KEYEVENTF_KEYUP, 0)
    user32.SetForegroundWindow(hwnd)


def close_window_by_title(substring: str, timeout: float = 5.0) -> bool:
    """Find and close the first window matching the title substring."""
    windows = find_windows_by_title(substring)
    for hwnd, _title in windows:
        user32.PostMessageW(hwnd, WM_CLOSE, 0, 0)
        deadline = time.monotonic() + timeout
        while time.monotonic() < deadline:
            time.sleep(0.3)
            if not user32.IsWindow(hwnd) or not user32.IsWindowVisible(hwnd):
                return True
    return False


def position_kicad_left(narration_width: int = 480) -> int | None:
    """Find the active KiCad editor and position it on the left side.

    Returns the hwnd if found, None otherwise.
    """
    screen_w, screen_h = get_screen_size()
    kicad_w = screen_w - narration_width

    # Try to find KiCad windows in priority order
    for title_part in [
        "PCB Editor",
        "pcbnew",
        "Schematic Editor",
        "eeschema",
        "Symbol Editor",
        "Footprint Editor",
        "KiCad",
    ]:
        windows = find_windows_by_title(title_part)
        for hwnd, title in windows:
            # Skip tiny windows and the narration panel itself
            if "Adom" in title and "Tour" in title:
                continue
            position_window(hwnd, 0, 0, kicad_w, screen_h)
            bring_to_front(hwnd)
            return hwnd
    return None