"""
keybindings.py — Keybinding definitions and persistence for Powernet.

File location
-------------
Same directory as settings.json, but keybindings.json:
  Windows : %APPDATA%\\Powernet\\keybindings.json
  macOS   : ~/Library/Application Support/Powernet/keybindings.json
  Linux   : $XDG_DATA_HOME/Powernet/keybindings.json

Rebindable actions
------------------
  tab_generators  — open Generators picker tab
  tab_research    — open Research picker tab
  tab_logistics   — open Logistics picker tab
  tab_wires       — open Wires/wire-draw mode
  bulldoze        — toggle Bulldoze tool
  pause_time      — pause/unpause in-game time
  debug           — open debug overlay (F5)

NOT rebindable: ESC (always pauses/cancels), F3 (global debug), F11 (fullscreen).
"""

from __future__ import annotations

import json
from typing import Optional

import pygame

from helpers.settings import app_data_dir  # type: ignore[import]

# ---------------------------------------------------------------------------
# Defaults
# ---------------------------------------------------------------------------

DEFAULT_KEYBINDINGS: dict[str, int] = {
    "tab_generators": pygame.K_1,
    "tab_research":   pygame.K_2,
    "tab_logistics":  pygame.K_3,
    "tab_wires":      pygame.K_4,
    "bulldoze":       pygame.K_5,
    "pause_time":     pygame.K_SPACE,
    "debug":          pygame.K_F5,
}

# Human-readable labels for each action (used in the Controls UI)
ACTION_LABELS: dict[str, str] = {
    "tab_generators": "Tab: Generators",
    "tab_research":   "Tab: Research",
    "tab_logistics":  "Tab: Logistics",
    "tab_wires":      "Tab: Wires",
    "bulldoze":       "Bulldoze Tool",
    "pause_time":     "Pause Time",
    "debug":          "Debug Menu",
}

_KB_FILE = app_data_dir() / "keybindings.json"

# ---------------------------------------------------------------------------
# Keybindings dict wrapper
# ---------------------------------------------------------------------------


class Keybindings:
    """Thin wrapper around a dict[str, int] with load/save support."""

    def __init__(self, data: Optional[dict[str, int]] = None) -> None:
        self._data: dict[str, int] = dict(DEFAULT_KEYBINDINGS)
        if data:
            # Only import known actions; ignore unknown / corrupt values
            for action, key in data.items():
                if action in DEFAULT_KEYBINDINGS and isinstance(key, int):
                    self._data[action] = key

    # dict-like access -------------------------------------------------------

    def __getitem__(self, action: str) -> int:
        return self._data.get(action, DEFAULT_KEYBINDINGS.get(action, pygame.K_UNKNOWN))

    def __setitem__(self, action: str, key: int) -> None:
        if action in DEFAULT_KEYBINDINGS:
            self._data[action] = key

    def __contains__(self, action: object) -> bool:
        return action in self._data

    def items(self):  # type: ignore[override]
        return self._data.items()

    # Persistence ------------------------------------------------------------

    def save(self) -> None:
        _KB_FILE.parent.mkdir(parents=True, exist_ok=True)
        with open(_KB_FILE, "w", encoding="utf-8") as fh:
            json.dump(self._data, fh, indent=2)

    @classmethod
    def load(cls) -> "Keybindings":
        if not _KB_FILE.exists():
            kb = cls()
            kb.save()
            return kb
        try:
            with open(_KB_FILE, encoding="utf-8") as fh:
                data = json.load(fh)
            return cls(data)
        except Exception:
            return cls()

    # Helpers ----------------------------------------------------------------

    def reset_to_defaults(self) -> None:
        """Overwrite all bindings with the defaults and save."""
        self._data = dict(DEFAULT_KEYBINDINGS)
        self.save()

    def is_default(self, action: str) -> bool:
        return self._data.get(action) == DEFAULT_KEYBINDINGS.get(action)


# ---------------------------------------------------------------------------
# Global singleton (lazy-loaded)
# ---------------------------------------------------------------------------

_instance: Optional[Keybindings] = None


def get_keybindings() -> Keybindings:
    global _instance
    if _instance is None:
        _instance = Keybindings.load()
    return _instance


def reload_keybindings() -> Keybindings:
    """Force reload from disk."""
    global _instance
    _instance = Keybindings.load()
    return _instance


# ---------------------------------------------------------------------------
# Utility: human-readable key name
# ---------------------------------------------------------------------------

# Special-case overrides for common keys
_KEY_NAMES: dict[int, str] = {
    pygame.K_SPACE:    "Space",
    pygame.K_RETURN:   "Enter",
    pygame.K_KP_ENTER: "Num Enter",
    pygame.K_BACKSPACE:"Backspace",
    pygame.K_TAB:      "Tab",
    pygame.K_ESCAPE:   "Escape",
    pygame.K_DELETE:   "Delete",
    pygame.K_INSERT:   "Insert",
    pygame.K_HOME:     "Home",
    pygame.K_END:      "End",
    pygame.K_PAGEUP:   "Page Up",
    pygame.K_PAGEDOWN: "Page Down",
    pygame.K_UP:       "Up",
    pygame.K_DOWN:     "Down",
    pygame.K_LEFT:     "Left",
    pygame.K_RIGHT:    "Right",
    pygame.K_F1:  "F1",  pygame.K_F2:  "F2",  pygame.K_F3:  "F3",
    pygame.K_F4:  "F4",  pygame.K_F5:  "F5",  pygame.K_F6:  "F6",
    pygame.K_F7:  "F7",  pygame.K_F8:  "F8",  pygame.K_F9:  "F9",
    pygame.K_F10: "F10", pygame.K_F11: "F11", pygame.K_F12: "F12",
    pygame.K_LSHIFT:   "L-Shift",  pygame.K_RSHIFT:   "R-Shift",
    pygame.K_LCTRL:    "L-Ctrl",   pygame.K_RCTRL:    "R-Ctrl",
    pygame.K_LALT:     "L-Alt",    pygame.K_RALT:     "R-Alt",
    pygame.K_CAPSLOCK: "Caps Lock",
    pygame.K_KP0: "Num 0", pygame.K_KP1: "Num 1", pygame.K_KP2: "Num 2",
    pygame.K_KP3: "Num 3", pygame.K_KP4: "Num 4", pygame.K_KP5: "Num 5",
    pygame.K_KP6: "Num 6", pygame.K_KP7: "Num 7", pygame.K_KP8: "Num 8",
    pygame.K_KP9: "Num 9",
}


def key_name(k: int) -> str:
    """Return a short human-readable name for pygame key constant *k*."""
    if k in _KEY_NAMES:
        return _KEY_NAMES[k]
    name = pygame.key.name(k)
    if name and name != "unknown key":
        # Capitalise single chars; upper-case short names that look like "a"
        return name.upper() if len(name) == 1 else name.capitalize()
    return f"Key {k}"
