"""Hotkey configuration — action registry, defaults, serialization, key mapping."""

from __future__ import annotations

from pynput.keyboard import Key, KeyCode


# ---------------------------------------------------------------------------
# Action registry — all configurable hotkey actions
# ---------------------------------------------------------------------------

ACTION_GROUPS = [
    ("group_ai_actions", [
        "trigger_query",
        "copy_and_query",
        "manual_recording",
        "toggle_code_mode",
    ]),
    ("group_screenshots", [
        "capture_screenshot",
    ]),
    ("group_navigation", [
        "scroll_up",
        "scroll_down",
        "nav_prev",
        "nav_next",
        "font_size_up",
        "font_size_down",
    ]),
    ("group_ui", [
        "toggle_overlay",
    ]),
]

def _action_label(action: str) -> str:
    from ai_interview.i18n import t
    return t(f"hk_{action}")

def _action_desc(action: str) -> str:
    from ai_interview.i18n import t
    return t(f"hk_{action}_desc")

ACTION_REGISTRY = {
    "trigger_query":    {"allowed_types": ["double_tap"],         "default": {"type": "double_tap",         "key": "cmd",   "beep": True}},
    "copy_and_query":   {"allowed_types": ["double_tap"],         "default": {"type": "double_tap",         "key": "ctrl",  "beep": True}},
    "manual_recording": {"allowed_types": ["press_hold_release"], "default": {"type": "press_hold_release", "key": "esc",   "beep": True}},
    "toggle_code_mode": {"allowed_types": ["combined"],           "default": {"type": "combined", "modifier": "esc", "key": "up",    "beep": False}},
    "capture_screenshot":{"allowed_types": ["combined"],          "default": {"type": "combined", "modifier": "esc", "key": "down",  "beep": True}},
    "scroll_up":        {"allowed_types": ["combined"],           "default": {"type": "combined", "modifier": "esc", "key": "left",  "beep": False}},
    "scroll_down":      {"allowed_types": ["combined"],           "default": {"type": "combined", "modifier": "esc", "key": "right", "beep": False}},
    "nav_prev":         {"allowed_types": ["combined"],           "default": {"type": "combined", "modifier": "esc", "key": "[",     "beep": False}},
    "nav_next":         {"allowed_types": ["combined"],           "default": {"type": "combined", "modifier": "esc", "key": "]",     "beep": False}},
    "font_size_up":     {"allowed_types": ["combined"],           "default": {"type": "combined", "modifier": "cmd", "key": "up",    "beep": False}},
    "font_size_down":   {"allowed_types": ["combined"],           "default": {"type": "combined", "modifier": "cmd", "key": "down",  "beep": False}},
    "toggle_overlay":   {"allowed_types": ["double_tap"],         "default": {"type": "double_tap",         "key": "esc",   "beep": False}},
}


# ---------------------------------------------------------------------------
# Key name ↔ pynput mapping
# ---------------------------------------------------------------------------

_KEY_TO_PYNPUT = {
    "esc": Key.esc,
    "cmd": Key.cmd, "cmd_l": Key.cmd_l, "cmd_r": Key.cmd_r,
    "ctrl": Key.ctrl, "ctrl_l": Key.ctrl_l, "ctrl_r": Key.ctrl_r,
    "alt": Key.alt, "alt_l": Key.alt_l, "alt_r": Key.alt_r,
    "shift": Key.shift, "shift_l": Key.shift_l, "shift_r": Key.shift_r,
    "up": Key.up, "down": Key.down, "left": Key.left, "right": Key.right,
    "space": Key.space, "tab": Key.tab, "enter": Key.enter,
    "backspace": Key.backspace, "delete": Key.delete,
    "f1": Key.f1, "f2": Key.f2, "f3": Key.f3, "f4": Key.f4,
    "f5": Key.f5, "f6": Key.f6, "f7": Key.f7, "f8": Key.f8,
    "f9": Key.f9, "f10": Key.f10, "f11": Key.f11, "f12": Key.f12,
}

_PYNPUT_TO_KEY = {v: k for k, v in _KEY_TO_PYNPUT.items()}

# Display names for UI
DISPLAY_NAMES = {
    "esc": "ESC", "cmd": "Cmd", "cmd_l": "Cmd", "cmd_r": "Cmd",
    "ctrl": "Ctrl", "ctrl_l": "Ctrl", "ctrl_r": "Ctrl",
    "alt": "Alt", "alt_l": "Alt", "alt_r": "Alt",
    "shift": "Shift", "shift_l": "Shift", "shift_r": "Shift",
    "up": "↑", "down": "↓", "left": "←", "right": "→",
    "space": "Space", "tab": "Tab", "enter": "Enter",
    "backspace": "⌫", "delete": "⌦",
}

def type_label(btype: str) -> str:
    from ai_interview.i18n import t
    return {"combined": t("type_combined"), "double_tap": t("type_double_tap"), "press_hold_release": t("type_press_hold")}.get(btype, btype)

# Keep for backward compat
TYPE_LABELS = {"combined": "Hold + Press", "double_tap": "Double Tap", "press_hold_release": "Tap + Hold"}


def key_name_to_pynput(name: str):
    """Convert canonical key name to pynput Key or KeyCode."""
    if name in _KEY_TO_PYNPUT:
        return _KEY_TO_PYNPUT[name]
    if len(name) == 1:
        return KeyCode.from_char(name)
    return None


def pynput_to_key_name(key) -> str:
    """Convert pynput Key/KeyCode to canonical string name."""
    if key in _PYNPUT_TO_KEY:
        return _PYNPUT_TO_KEY[key]
    if hasattr(key, "char") and key.char:
        return key.char
    return str(key).replace("Key.", "")


def key_display_name(name: str) -> str:
    """Human-readable name for a key."""
    return DISPLAY_NAMES.get(name, name.upper() if len(name) == 1 else name)


def binding_display_string(binding: dict) -> str:
    """Human-readable string for a full binding, e.g. 'ESC + ↓' or '2× Cmd'."""
    btype = binding.get("type", "")
    key = binding.get("key", "")
    modifier = binding.get("modifier", "")

    if btype == "combined":
        return f"{key_display_name(modifier)} + {key_display_name(key)}"
    elif btype == "double_tap":
        return f"2× {key_display_name(key)}"
    elif btype == "press_hold_release":
        return f"2× {key_display_name(key)} + Hold"
    return "?"


# ---------------------------------------------------------------------------
# Config I/O
# ---------------------------------------------------------------------------

def get_defaults() -> dict:
    """Return default hotkey bindings for all actions."""
    return {action: dict(info["default"]) for action, info in ACTION_REGISTRY.items()}


def load_hotkeys(config: dict) -> dict:
    """Load hotkeys from config dict, filling missing actions with defaults."""
    defaults = get_defaults()
    saved = config.get("hotkeys", {})
    result = {}
    for action, default_binding in defaults.items():
        if action in saved:
            binding = saved[action]
            # Validate trigger type
            allowed = ACTION_REGISTRY[action]["allowed_types"]
            if binding.get("type") not in allowed:
                binding = default_binding
            result[action] = binding
        else:
            result[action] = default_binding
    return result


def save_hotkeys(config: dict, hotkeys: dict) -> None:
    """Write hotkeys to config dict (caller must call save_config)."""
    config["hotkeys"] = hotkeys


def validate_binding(action: str, binding: dict) -> list[str]:
    """Return list of error strings (empty = valid)."""
    errors = []
    if action not in ACTION_REGISTRY:
        errors.append(f"Unknown action: {action}")
        return errors

    info = ACTION_REGISTRY[action]
    btype = binding.get("type", "")
    if btype not in info["allowed_types"]:
        errors.append(f"Trigger type '{btype}' not allowed for '{action}'")

    if btype == "combined":
        if not binding.get("modifier"):
            errors.append("Combined binding requires a modifier key")
        if not binding.get("key"):
            errors.append("Combined binding requires a trigger key")
    elif btype in ("double_tap", "press_hold_release"):
        if not binding.get("key"):
            errors.append("Binding requires a key")

    return errors


def check_conflicts(hotkeys: dict) -> list[tuple[str, str]]:
    """Return list of (action1, action2) pairs that conflict."""
    conflicts = []
    actions = list(hotkeys.keys())
    for i, a1 in enumerate(actions):
        for a2 in actions[i + 1:]:
            b1, b2 = hotkeys[a1], hotkeys[a2]
            if b1.get("type") != b2.get("type"):
                continue
            if b1.get("type") == "combined":
                if b1.get("modifier") == b2.get("modifier") and b1.get("key") == b2.get("key"):
                    conflicts.append((a1, a2))
            elif b1.get("key") == b2.get("key"):
                # double_tap and press_hold_release on same key is OK (different gesture)
                if b1.get("type") == b2.get("type"):
                    conflicts.append((a1, a2))
    return conflicts


# ---------------------------------------------------------------------------
# Flet keyboard event → canonical key name mapping
# ---------------------------------------------------------------------------

_FLET_KEY_MAP = {
    "Escape": "esc",
    "Arrow Up": "up", "Arrow Down": "down", "Arrow Left": "left", "Arrow Right": "right",
    "Meta Left": "cmd", "Meta Right": "cmd",
    "Control Left": "ctrl", "Control Right": "ctrl",
    "Alt Left": "alt", "Alt Right": "alt",
    "Shift Left": "shift", "Shift Right": "shift",
    "Space": "space", "Tab": "tab", "Enter": "enter",
    "Backspace": "backspace", "Delete": "delete",
    "F1": "f1", "F2": "f2", "F3": "f3", "F4": "f4",
    "F5": "f5", "F6": "f6", "F7": "f7", "F8": "f8",
    "F9": "f9", "F10": "f10", "F11": "f11", "F12": "f12",
    "Bracket Left": "[", "Bracket Right": "]",
    "Minus": "-", "Equal": "=", "Slash": "/", "Backslash": "\\",
    "Semicolon": ";", "Quote": "'", "Comma": ",", "Period": ".",
    "Backquote": "`",
}


def flet_key_to_name(flet_key: str) -> str:
    """Convert Flet keyboard event key string to canonical name."""
    if flet_key in _FLET_KEY_MAP:
        return _FLET_KEY_MAP[flet_key]
    # Single character keys (a-z, 0-9)
    if len(flet_key) == 1:
        return flet_key.lower()
    # "Key X" format
    if flet_key.startswith("Key ") and len(flet_key) == 5:
        return flet_key[-1].lower()
    return flet_key.lower()
