import { useEffect, useRef } from 'react'

/**
 * Регистрирует глобальные клавиатурные сокращения. Поддерживаемые формы:
 *  - 'Escape' | 'Enter' | 'F1' …
 *  - 'mod+s'   — Ctrl+S на Linux/Win, Cmd+S на Mac
 *  - 'mod+shift+s'
 *  - 'n', '/', '?' (одиночные клавиши БЕЗ модификаторов)
 *
 * Особенности:
 *  - Одиночные клавиши срабатывают только если фокус НЕ в input/textarea/
 *    contenteditable (чтобы не ломать набор текста). 'Escape' и mod+*
 *    срабатывают всегда.
 *  - preventDefault() вызывается автоматически — handler решает только что
 *    делать, без боли с e.preventDefault().
 *  - При unmount хук снимает listener.
 *
 * Использование:
 *   useShortcuts({
 *     'mod+s':   () => save.mutate(),
 *     'Escape':  () => navigate(-1),
 *     '/':       () => searchRef.current?.focus(),
 *     'n':       () => navigate('/catalog/products/new'),
 *   })
 */
type Handler = (e: KeyboardEvent) => void
type Map = Record<string, Handler>

const isTypingTarget = (el: EventTarget | null): boolean => {
  if (!(el instanceof HTMLElement)) return false
  const tag = el.tagName
  if (tag === 'INPUT' || tag === 'TEXTAREA' || tag === 'SELECT') return true
  if (el.isContentEditable) return true
  return false
}

const matches = (e: KeyboardEvent, spec: string): boolean => {
  const parts = spec.toLowerCase().split('+').map(s => s.trim())
  const wantMod = parts.includes('mod')
  const wantShift = parts.includes('shift')
  const wantAlt = parts.includes('alt')
  const key = parts[parts.length - 1]
  const isBare = parts.length === 1

  // Бэр-ключи ('?', '/', 'n', 'Escape') — не зависим от модификаторов:
  // некоторые символы требуют shift на ряде раскладок ('?'), и мы хотим
  // чтобы ловилось при любом состоянии. Esc сам не использует модификаторы.
  if (isBare) {
    return e.key.toLowerCase() === key
  }

  const ctrlOrMeta = e.ctrlKey || e.metaKey
  if (wantMod !== ctrlOrMeta) return false
  if (wantShift !== e.shiftKey) return false
  if (wantAlt !== e.altKey) return false

  // 'mod+s' → e.key === 's' (lowercase)
  return e.key.toLowerCase() === key
}

export function useShortcuts(map: Map, enabled = true) {
  // Держим map в ref, чтобы не перерегистрировать listener на каждый рендер
  // (handlers часто захватывают свежие props/state — но useEffect deps
  // делает их стабильными).
  const ref = useRef(map)
  ref.current = map

  useEffect(() => {
    if (!enabled) return
    const onKey = (e: KeyboardEvent) => {
      for (const [spec, handler] of Object.entries(ref.current)) {
        const isBareKey = !spec.includes('+') && spec.length === 1
        // Бэр-клавиши ('n', '/', '?') не должны срабатывать в input'ах.
        if (isBareKey && isTypingTarget(e.target)) continue
        if (matches(e, spec)) {
          e.preventDefault()
          handler(e)
          return
        }
      }
    }
    document.addEventListener('keydown', onKey)
    return () => document.removeEventListener('keydown', onKey)
  }, [enabled])
}
