"""Windows: capture currently selected text via Ctrl+C + clipboard polling."""

from __future__ import annotations

import ctypes
import logging
import time

log = logging.getLogger(__name__)

_VK_CONTROL = 0x11
_VK_C = 0x43
_KEYEVENTF_KEYUP = 0x0002

_POLL_INTERVAL = 0.05  # seconds between clipboard checks
_POLL_ATTEMPTS = 12  # total wait = 0.6s


def _keybd_event(vk: int, keyup: bool = False) -> None:
    """Send a keyboard event via keybd_event (simple, no HWND needed)."""
    flags = _KEYEVENTF_KEYUP if keyup else 0
    ctypes.windll.user32.keybd_event(vk, 0, flags, 0)  # type: ignore[attr-defined]


def _simulate_ctrl_c() -> None:
    """Press and release Ctrl+C to copy selected text."""
    _keybd_event(_VK_CONTROL)
    _keybd_event(_VK_C)
    time.sleep(0.05)
    _keybd_event(_VK_C, keyup=True)
    _keybd_event(_VK_CONTROL, keyup=True)


def _clipboard_read() -> str:
    """Read text from Windows clipboard using ctypes."""
    try:
        import pyperclip

        return pyperclip.paste() or ""
    except Exception:
        return _clipboard_read_raw()


def _clipboard_read_raw() -> str:
    """Fallback: read clipboard via Win32 API directly."""
    CF_UNICODETEXT = 13
    user32 = ctypes.windll.user32  # type: ignore[attr-defined]
    kernel32 = ctypes.windll.kernel32  # type: ignore[attr-defined]

    if not user32.OpenClipboard(None):
        return ""
    try:
        h_data = user32.GetClipboardData(CF_UNICODETEXT)
        if not h_data:
            return ""
        ptr = kernel32.GlobalLock(h_data)
        if not ptr:
            return ""
        try:
            return ctypes.wstring_at(ptr)
        finally:
            kernel32.GlobalUnlock(h_data)
    finally:
        user32.CloseClipboard()


def _clipboard_write_raw(text: str) -> None:
    """Write text to Windows clipboard via Win32 API directly."""
    CF_UNICODETEXT = 13
    GMEM_MOVEABLE = 0x0002
    user32 = ctypes.windll.user32  # type: ignore[attr-defined]
    kernel32 = ctypes.windll.kernel32  # type: ignore[attr-defined]

    try:
        encoded = text.encode("utf-16-le") + b"\x00\x00"
        size = len(encoded)
        h_mem = kernel32.GlobalAlloc(GMEM_MOVEABLE, size)
        if not h_mem:
            return
        ptr = kernel32.GlobalLock(h_mem)
        if not ptr:
            kernel32.GlobalFree(h_mem)
            return
        ctypes.memmove(ptr, encoded, size)
        kernel32.GlobalUnlock(h_mem)

        if not user32.OpenClipboard(None):
            kernel32.GlobalFree(h_mem)
            return
        try:
            user32.EmptyClipboard()
            user32.SetClipboardData(CF_UNICODETEXT, h_mem)
        finally:
            user32.CloseClipboard()
    except Exception as exc:
        log.debug("_clipboard_write_raw failed: %s", exc)


def _clipboard_write(text: str) -> None:
    """Write text to Windows clipboard using pyperclip or Win32 fallback."""
    try:
        import pyperclip

        pyperclip.copy(text)
    except Exception:
        _clipboard_write_raw(text)


def get_selected_text() -> str:
    """Return currently selected text by simulating Ctrl+C.

    Polls the clipboard for up to 0.6s waiting for the content to change.
    Returns empty string if nothing was selected or clipboard didn't change.
    """
    before = _clipboard_read()
    log.info("Ctrl+C capture: clipboard before=%r", before[:30] if before else "")

    _simulate_ctrl_c()

    captured = ""
    for _ in range(_POLL_ATTEMPTS):
        time.sleep(_POLL_INTERVAL)
        current = _clipboard_read()
        if current and current != before:
            log.info("Captured %d chars from selection", len(current))
            captured = current
            break

    if not captured:
        log.debug("No selection captured (clipboard unchanged)")

    if before:
        _clipboard_write(before)

    return captured
