"""Hotkeys screen — view and customize keyboard shortcuts via key capture."""

from __future__ import annotations

import flet as ft

from ai_interview.config import load_saved_config, save_config
from ai_interview.i18n import t
from ai_interview.hotkey_config import (
    ACTION_GROUPS,
    ACTION_REGISTRY,
    _action_label,
    _action_desc,
    type_label,
    binding_display_string,
    check_conflicts,
    flet_key_to_name,
    key_display_name,
    load_hotkeys,
    save_hotkeys,
)

TEAL = "#4ec9b0"
MUTED = "#8b949e"
SZ = 13


class HotkeysScreen(ft.Column):
    """View and customize keyboard shortcuts with live key capture."""

    def __init__(self, page: ft.Page, saved_config: dict):
        super().__init__(
            expand=True,
            scroll=ft.ScrollMode.AUTO,
            spacing=20,
            horizontal_alignment=ft.CrossAxisAlignment.STRETCH,
        )
        self._page = page
        self._config = saved_config
        self._hotkeys = load_hotkeys(saved_config)
        self._capturing_action = None
        self._pending_modifier = None  # for combined: modifier pressed, waiting for key

        group_cards = []
        self._labels = {}
        self._buttons = {}
        self._beeps = {}

        _tap_keys = ["esc", "cmd", "ctrl", "alt", "shift", "space", "tab",
                     "f1", "f2", "f3", "f4", "f5", "f6", "f7", "f8", "f9", "f10", "f11", "f12"]

        for group_name, actions in ACTION_GROUPS:
            group_rows = []
            for action in actions:
                info = ACTION_REGISTRY[action]
                binding = self._hotkeys.get(action, info["default"])

                name_col = ft.Column([
                    ft.Text(_action_label(action), size=SZ, weight=ft.FontWeight.W_500),
                    ft.Text(_action_desc(action), size=10, color=MUTED),
                ], spacing=2, width=220)

                if binding["type"] == "combined":
                    btn_label = ft.Text(binding_display_string(binding), size=SZ)
                    key_widget = ft.OutlinedButton(
                        content=btn_label,
                        on_click=lambda e, a=action: self._start_capture(a),
                        expand=True,
                    )
                    self._labels[action] = btn_label
                    self._buttons[action] = key_widget
                else:
                    dd = ft.Dropdown(
                        value=binding.get("key", "cmd"),
                        options=[ft.dropdown.Option(k, key_display_name(k)) for k in _tap_keys],
                        width=120, text_size=SZ, border_radius=8, dense=True,
                        on_select=lambda e, a=action: self._on_dd_change(a, e),
                    )
                    gesture_label = ft.Container(
                        content=ft.Text(
                            type_label(binding["type"]),
                            size=10, color=TEAL, weight=ft.FontWeight.W_600,
                        ),
                        bgcolor="#1c2128",
                        border=ft.border.all(1, TEAL),
                        border_radius=12,
                        padding=ft.padding.symmetric(horizontal=8, vertical=4),
                    )
                    key_widget = ft.Row(
                        [dd, gesture_label],
                        spacing=8,
                        expand=True,
                        vertical_alignment=ft.CrossAxisAlignment.CENTER,
                    )
                    self._buttons[action] = dd

                beep_cb = ft.Checkbox(
                    value=binding.get("beep", False),
                    label="🔊", tooltip="Beep feedback",
                    on_change=lambda e, a=action: self._on_beep_toggle(a, e),
                )
                self._beeps[action] = beep_cb

                reset_btn = ft.IconButton(
                    icon=ft.Icons.RESTART_ALT, icon_size=16,
                    tooltip=t("reset_default"),
                    on_click=lambda e, a=action: self._reset_action(a),
                )

                group_rows.append(
                    ft.Row([name_col, key_widget, beep_cb, reset_btn], spacing=8,
                           vertical_alignment=ft.CrossAxisAlignment.CENTER)
                )

            group_cards.append(
                ft.Card(
                    content=ft.Container(
                        content=ft.Column([
                            ft.Text(t(group_name), size=12, weight=ft.FontWeight.W_600, color=MUTED),
                            *group_rows,
                        ], spacing=8),
                        padding=20,
                    ),
                )
            )

        self._conflict_text = ft.Text("", size=11, color="#f14c4c", visible=False)
        self._capture_banner = ft.Container(
            content=ft.Text(
                t("press_keys"),
                size=14, weight=ft.FontWeight.W_600, color=TEAL,
                text_align=ft.TextAlign.CENTER,
            ),
            bgcolor="#1c2128",
            border=ft.border.all(2, TEAL),
            border_radius=8,
            padding=16,
            visible=False,
        )
        self._session_note = ft.Text(
            t("hotkeys_readonly"),
            size=11, color="#d29922", visible=False,
        )

        self.controls = [
            ft.Container(
                content=ft.Column([
                    ft.Text(t("hotkeys"), size=22, weight=ft.FontWeight.W_600),
                    self._session_note,
                    self._capture_banner,
                    *group_cards,
                    self._conflict_text,
                ], spacing=14, horizontal_alignment=ft.CrossAxisAlignment.STRETCH),
                padding=30,
            ),
        ]

    def on_activate(self):
        fresh = load_saved_config()
        self._hotkeys = load_hotkeys(fresh)
        for action, binding in self._hotkeys.items():
            if action in self._labels:
                self._labels[action].value = binding_display_string(binding)
            elif binding["type"] != "combined":
                # Dropdown widget
                w = self._buttons.get(action)
                if w and hasattr(w, "value"):
                    w.value = binding.get("key", "cmd")
            if action in self._beeps:
                self._beeps[action].value = binding.get("beep", False)
        self._stop_capture()
        try:
            self._page.update()
        except Exception:
            pass

    def _start_capture(self, action: str):
        if self._buttons[action].disabled:
            return
        self._stop_capture()
        self._capturing_action = action
        self._pending_modifier = None
        self._labels[action].value = "..."
        self._capture_banner.visible = True
        self._page.on_keyboard_event = self._on_key_capture
        self._page.update()

    def _on_key_capture(self, e):
        if not self._capturing_action:
            return

        action = self._capturing_action
        key_name = flet_key_to_name(e.key)
        binding = dict(self._hotkeys[action])

        # Detect modifier flags
        modifier = None
        if e.meta:
            modifier = "cmd"
        elif e.ctrl:
            modifier = "ctrl"
        elif e.alt:
            modifier = "alt"
        elif e.shift:
            modifier = "shift"

        # Check if the pressed key itself is a modifier name (e.g. key='Escape')
        is_special = key_name in ("esc", "cmd", "ctrl", "alt", "shift",
                                   "cmd_l", "cmd_r", "ctrl_l", "ctrl_r",
                                   "alt_l", "alt_r", "shift_l", "shift_r")

        if binding["type"] == "combined":
            if modifier and not is_special:
                # Modifier + actual key pressed together (e.g. Cmd+K)
                binding["modifier"] = modifier
                binding["key"] = key_name
                self._apply(action, binding)
            elif is_special and not modifier:
                # Standalone special key (ESC, Cmd, etc.) — wait for second key
                self._pending_modifier = key_name.split("_")[0]
                self._labels[action].value = f"{key_display_name(self._pending_modifier)} + ..."
                self._page.update()
            elif self._pending_modifier and not is_special:
                # Second key after modifier (e.g. pressed ESC, now pressing K)
                binding["modifier"] = self._pending_modifier
                binding["key"] = key_name
                self._apply(action, binding)
            else:
                binding["key"] = key_name
                self._apply(action, binding)
        else:
            # double_tap / press_hold_release — capture ANY single key immediately
            if modifier:
                binding["key"] = modifier
            else:
                binding["key"] = key_name.split("_")[0]
            self._apply(action, binding)

    def _apply(self, action: str, binding: dict):
        self._hotkeys[action] = binding
        self._labels[action].value = binding_display_string(binding)
        self._capture_banner.visible = False
        self._capturing_action = None
        self._pending_modifier = None
        self._page.on_keyboard_event = None

        conflicts = check_conflicts(self._hotkeys)
        if conflicts:
            names = ", ".join(
                f"{ACTION_REGISTRY[a]['label']} & {ACTION_REGISTRY[b]['label']}"
                for a, b in conflicts
            )
            self._conflict_text.value = f"⚠ Conflict: {names}"
            self._conflict_text.visible = True
        else:
            self._conflict_text.visible = False

        save_hotkeys(self._config, self._hotkeys)
        save_config(self._config)
        try:
            self._page.update()
        except Exception:
            pass

    def _stop_capture(self):
        if self._capturing_action and self._capturing_action in self._labels:
            self._labels[self._capturing_action].value = binding_display_string(
                self._hotkeys[self._capturing_action]
            )
        self._capture_banner.visible = False
        self._capturing_action = None
        self._pending_modifier = None
        self._page.on_keyboard_event = None

    def _on_dd_change(self, action: str, e):
        binding = dict(self._hotkeys[action])
        binding["key"] = e.control.value
        self._hotkeys[action] = binding

        conflicts = check_conflicts(self._hotkeys)
        if conflicts:
            names = ", ".join(
                f"{ACTION_REGISTRY[a]['label']} & {ACTION_REGISTRY[b]['label']}"
                for a, b in conflicts
            )
            self._conflict_text.value = f"⚠ Conflict: {names}"
            self._conflict_text.visible = True
        else:
            self._conflict_text.visible = False

        save_hotkeys(self._config, self._hotkeys)
        save_config(self._config)
        try:
            self._page.update()
        except Exception:
            pass

    def _reset_action(self, action: str):
        default = dict(ACTION_REGISTRY[action]["default"])
        self._hotkeys[action] = default
        if action in self._labels:
            self._labels[action].value = binding_display_string(default)
        else:
            w = self._buttons.get(action)
            if w and hasattr(w, "value"):
                w.value = default.get("key", "cmd")
        self._beeps[action].value = default.get("beep", False)

        conflicts = check_conflicts(self._hotkeys)
        self._conflict_text.visible = bool(conflicts)
        if conflicts:
            names = ", ".join(
                f"{ACTION_REGISTRY[a]['label']} & {ACTION_REGISTRY[b]['label']}"
                for a, b in conflicts
            )
            self._conflict_text.value = f"⚠ Conflict: {names}"

        save_hotkeys(self._config, self._hotkeys)
        save_config(self._config)
        self._page.update()

    def _on_beep_toggle(self, action: str, e):
        self._hotkeys[action]["beep"] = e.control.value
        save_hotkeys(self._config, self._hotkeys)
        save_config(self._config)

    def update_session_state(self, running: bool):
        for btn in self._buttons.values():
            btn.disabled = running
        for cb in self._beeps.values():
            cb.disabled = running
        self._session_note.visible = running
        if running:
            self._stop_capture()
        try:
            self._page.update()
        except Exception:
            pass
