import { useEffect, useState } from 'react'
import { Trash2, RotateCcw } from '../../../lib/icons'
import { Section, Row, SubHeading } from '../_ui'
import { usePreferencesStore } from '../../../stores/preferences-store'
import { SHORTCUTS, eventToBinding, normalizeBinding, type ShortcutCategory } from '../../../lib/player-shortcuts'
import { toast } from '../../../stores/toast-store'

/**
 * Keyboard shortcut remapping. The bindings live in
 * `prefs.keyboardShortcuts` keyed by shortcut id. If a shortcut has an
 * entry, it overrides the default keys; if not, the shortcut's built-in
 * defaults apply.
 *
 * Editing flow: click a row to arm capture, press a key combo, the new
 * binding is normalised + stored. Esc aborts the capture without
 * changing anything. The capture intentionally ignores modifier-only
 * presses so users can't accidentally lock themselves into a binding
 * like `Ctrl` alone.
 */

const CATEGORY_LABELS: Record<ShortcutCategory, string> = {
  playback: 'Playback',
  audio: 'Audio',
  subtitles: 'Subtitles',
  view: 'View',
  tools: 'Tools',
  navigation: 'Navigation',
}

const CATEGORY_ORDER: ShortcutCategory[] = [
  'playback',
  'audio',
  'subtitles',
  'view',
  'tools',
  'navigation',
]

function prettyToken(t: string): string {
  if (t === ' ' || t.toLowerCase() === 'space') return 'Space'
  if (t === 'ArrowLeft') return '←'
  if (t === 'ArrowRight') return '→'
  if (t === 'ArrowUp') return '↑'
  if (t === 'ArrowDown') return '↓'
  if (t === 'Escape') return 'Esc'
  return t
}

function Kbd({ children }: { children: React.ReactNode }) {
  return (
    <kbd className="inline-flex items-center justify-center min-w-[22px] h-6 px-1.5 rounded text-[10.5px] font-mono font-medium text-text-1 bg-elevated border border-border tabular-nums">
      {children}
    </kbd>
  )
}

function BindingChips({ binding }: { binding: string }) {
  return (
    <span className="flex items-center gap-1">
      {binding.split('+').map((tok, i) => (
        <Kbd key={i}>{prettyToken(tok)}</Kbd>
      ))}
    </span>
  )
}

export function ShortcutsSection() {
  const overrides = usePreferencesStore(s => s.keyboardShortcuts)
  const setPreference = usePreferencesStore(s => s.setPreference)
  const [capturingId, setCapturingId] = useState<string | null>(null)

  function reset(id: string) {
    const next = { ...overrides }
    delete next[id]
    setPreference('keyboardShortcuts', next)
  }

  function resetAll() {
    setPreference('keyboardShortcuts', {})
    toast('All shortcuts reset to defaults', 'success')
  }

  useEffect(() => {
    if (!capturingId) return
    const id = capturingId
    function commit(binding: string) {
      const conflict = Object.entries({ ...overrides })
        .filter(([k]) => k !== id)
        .find(([, keys]) => (keys as string[]).some(k => normalizeBinding(k) === binding))
      const defaultConflict = SHORTCUTS.find(sc => sc.id !== id && sc.keys.some(k => normalizeBinding(k) === binding) && !overrides[sc.id])
      if (conflict) {
        const other = SHORTCUTS.find(s => s.id === conflict[0])
        toast(`That combo is bound to "${other?.description || conflict[0]}"`, 'error')
        return
      }
      if (defaultConflict) {
        toast(`That combo is bound to "${defaultConflict.description}"`, 'error')
        return
      }
      setPreference('keyboardShortcuts', { ...overrides, [id]: [binding] })
      toast('Shortcut updated', 'success')
    }
    function onKey(e: KeyboardEvent) {
      e.preventDefault()
      e.stopPropagation()
      if (e.key === 'Escape') {
        setCapturingId(null)
        return
      }
      if (e.key === 'Shift' || e.key === 'Control' || e.key === 'Alt' || e.key === 'Meta') {
        return
      }
      const binding = eventToBinding(e)
      setCapturingId(null)
      commit(binding)
    }
    window.addEventListener('keydown', onKey, true)
    return () => window.removeEventListener('keydown', onKey, true)
  }, [capturingId, overrides, setPreference])

  return (
    <Section
      id="shortcuts"
      title="Keyboard shortcuts"
      description="Remap player shortcuts. Click any binding to capture a new key combo - press Esc to cancel."
    >
      <Row label="Reset all to defaults" hint={`${Object.keys(overrides).length} custom ${Object.keys(overrides).length === 1 ? 'binding' : 'bindings'}`}>
        <button
          onClick={resetAll}
          disabled={Object.keys(overrides).length === 0}
          className="inline-flex items-center gap-1.5 h-9 px-3 rounded-md text-[12px] font-medium bg-elevated/60 text-text-2 border border-border hover:border-border-hover hover:text-text-1 transition-all duration-150 focus-ring disabled:opacity-40 disabled:cursor-not-allowed"
        >
          <RotateCcw size={13} stroke={2} />
          Reset all
        </button>
      </Row>

      {CATEGORY_ORDER.map(cat => {
        const items = SHORTCUTS.filter(s => s.category === cat)
        if (items.length === 0) return null
        return (
          <div key={cat}>
            <SubHeading label={CATEGORY_LABELS[cat]} />
            {items.map(sc => {
              const override = overrides[sc.id]
              const keys = override?.length ? override : sc.keys
              const isCustom = !!override?.length
              const isCapturing = capturingId === sc.id
              return (
                <Row key={sc.id} label={sc.description} hint={isCustom ? 'Custom binding' : undefined}>
                  <div className="flex items-center gap-2">
                    <button
                      onClick={() => setCapturingId(isCapturing ? null : sc.id)}
                      className={`min-h-[32px] inline-flex items-center justify-center gap-1.5 h-8 px-2.5 rounded-md text-[11.5px] font-medium border transition-colors duration-150 focus-ring ${
                        isCapturing
                          ? 'bg-accent/15 text-accent border-accent/40'
                          : 'bg-elevated/40 text-text-2 border-border hover:border-border-hover hover:text-text-1'
                      }`}
                    >
                      {isCapturing ? (
                        <span className="text-[11.5px] italic">Press a key...</span>
                      ) : (
                        <BindingChips binding={normalizeBinding(keys[0])} />
                      )}
                    </button>
                    {isCustom && !isCapturing && (
                      <button
                        onClick={() => reset(sc.id)}
                        title="Reset to default"
                        aria-label="Reset to default"
                        className="w-8 h-8 grid place-items-center rounded-md text-text-3 hover:text-text-1 hover:bg-elevated/60 transition-colors focus-ring"
                      >
                        <Trash2 size={13} stroke={2} />
                      </button>
                    )}
                  </div>
                </Row>
              )
            })}
          </div>
        )
      })}
    </Section>
  )
}
