"""Keyboard input tools."""

from fastmcp import Context
from fastmcp.exceptions import ToolError

from mcvnc._state import get_state, mcp

# Friendly aliases -> asyncvnc2 keysym names.
# asyncvnc2 already handles: Del, Esc, Cmd, Alt, Ctrl, Super, Shift, Backspace
# We add common lowercase/shorthand aliases the model might use.
KEY_ALIASES: dict[str, str] = {
    "enter": "Return",
    "return": "Return",
    "tab": "Tab",
    "space": "space",
    "esc": "Escape",
    "escape": "Escape",
    "backspace": "BackSpace",
    "delete": "Delete",
    "del": "Delete",
    "insert": "Insert",
    "home": "Home",
    "end": "End",
    "pageup": "Page_Up",
    "pagedown": "Page_Down",
    "up": "Up",
    "down": "Down",
    "left": "Left",
    "right": "Right",
    "ctrl": "Control_L",
    "control": "Control_L",
    "alt": "Alt_L",
    "shift": "Shift_L",
    "super": "Super_L",
    "meta": "Super_L",
    "cmd": "Super_L",
    "win": "Super_L",
    "capslock": "Caps_Lock",
    "numlock": "Num_Lock",
    "scrolllock": "Scroll_Lock",
    "printscreen": "Print",
    "pause": "Pause",
    "menu": "Menu",
}

# Add F1-F24
for _i in range(1, 25):
    KEY_ALIASES[f"f{_i}"] = f"F{_i}"


def _resolve_key(key: str) -> str:
    """Resolve a key name through the alias table."""
    return KEY_ALIASES.get(key.lower(), key)


@mcp.tool()
async def vnc_type_text(ctx: Context, session_id: str, text: str) -> str:
    """Type text on the remote desktop, character by character.

    For special keys (Enter, Tab, etc.) use vnc_press_key instead.
    For key combinations (Ctrl+C) use vnc_key_combo instead.

    Args:
        session_id: VNC session to type into.
        text: Text to type.
    """
    state = get_state(ctx)
    session = state.get(session_id)

    if not text:
        raise ToolError("text cannot be empty")

    async with session.lock:
        try:
            session.client.keyboard.write(text)
        except KeyError as e:
            raise ToolError(
                f"Unsupported character {e}. "
                f"vnc_type_text only supports characters with X11 keysym mappings. "
                f"Remove unsupported characters and try again."
            )
        await session.client.drain()

    return f"Typed {len(text)} characters"


@mcp.tool()
async def vnc_press_key(ctx: Context, session_id: str, key: str) -> str:
    """Press and release a single key.

    Supports key names like: Return, Tab, Escape, F1-F24, Up, Down, Left, Right,
    Home, End, Page_Up, Page_Down, Insert, Delete, BackSpace, and standard aliases
    (enter, esc, ctrl, alt, shift, etc.).

    Args:
        session_id: VNC session.
        key: Key name to press.
    """
    state = get_state(ctx)
    session = state.get(session_id)

    resolved = _resolve_key(key)
    async with session.lock:
        try:
            session.client.keyboard.press(resolved)
            await session.client.drain()
        except Exception as e:
            raise ToolError(f"Key press failed for '{key}' (resolved: '{resolved}'): {e}")

    return f"Pressed '{resolved}'"


@mcp.tool()
async def vnc_key_combo(ctx: Context, session_id: str, keys: list[str]) -> str:
    """Press a key combination (e.g. Ctrl+C, Alt+F4).

    All keys are pressed simultaneously and released in reverse order.

    Args:
        session_id: VNC session.
        keys: List of key names to press together, e.g. ["ctrl", "c"] or ["alt", "F4"].
    """
    state = get_state(ctx)
    session = state.get(session_id)

    if not keys or len(keys) < 2:
        raise ToolError("keys must contain at least 2 keys for a combo")

    resolved = [_resolve_key(k) for k in keys]
    async with session.lock:
        try:
            session.client.keyboard.press(*resolved)
            await session.client.drain()
        except Exception as e:
            raise ToolError(f"Key combo failed for {keys} (resolved: {resolved}): {e}")

    return f"Pressed combo: {' + '.join(resolved)}"
