<script lang="ts">
  import { keybindingStore, chordFromEvent, formatChord, chordParts, type Keybinding } from '../keybinding-store.svelte.ts';

  // ── State ─────────────────────────────────────────────────────
  let searchQuery = $state('');
  let capturingId = $state<string | null>(null);
  let conflictWarning = $state<string | null>(null);
  // Chord capture: first key of a multi-key sequence
  let capturePrefix = $state<string | null>(null);
  let capturePrefixTimer = $state<ReturnType<typeof setTimeout> | null>(null);

  // ── Derived filtered list ──────────────────────────────────────
  let filtered = $derived(
    searchQuery.trim()
      ? keybindingStore.bindings.filter(
          (b) =>
            b.label.toLowerCase().includes(searchQuery.toLowerCase()) ||
            b.category.toLowerCase().includes(searchQuery.toLowerCase()) ||
            b.chord.toLowerCase().includes(searchQuery.toLowerCase())
        )
      : keybindingStore.bindings
  );

  // ── Category groups ────────────────────────────────────────────
  let grouped = $derived(
    filtered.reduce<Record<string, Keybinding[]>>((acc, b) => {
      (acc[b.category] ??= []).push(b);
      return acc;
    }, {})
  );

  const CATEGORY_ORDER = ['Global', 'Navigation', 'Terminal', 'Settings'];

  // Known chord prefixes for multi-key detection
  const KNOWN_PREFIXES = ['Ctrl+K', 'Ctrl+Shift+K'];

  function isKnownPrefix(chord: string): boolean {
    return KNOWN_PREFIXES.includes(chord);
  }

  // ── Capture mode ──────────────────────────────────────────────
  function startCapture(id: string) {
    capturingId = id;
    conflictWarning = null;
    capturePrefix = null;
    if (capturePrefixTimer) clearTimeout(capturePrefixTimer);
    capturePrefixTimer = null;
  }

  function clearCapture() {
    capturingId = null;
    conflictWarning = null;
    capturePrefix = null;
    if (capturePrefixTimer) clearTimeout(capturePrefixTimer);
    capturePrefixTimer = null;
  }

  function handleCaptureKeydown(e: KeyboardEvent, id: string) {
    e.preventDefault();
    e.stopPropagation();

    const chord = chordFromEvent(e);
    if (!chord || chord === 'Escape') {
      clearCapture();
      return;
    }
    // Skip bare modifier key presses (no actual key yet)
    if (!chord.match(/[A-Z0-9,.\[\]\\/'`\-=; ]|F\d+|Enter|Tab|Space|Backspace|Delete|Arrow/)) {
      return;
    }

    // If we already have a prefix, complete the chord sequence
    if (capturePrefix) {
      if (capturePrefixTimer) clearTimeout(capturePrefixTimer);
      const fullChord = `${capturePrefix} ${chord}`;
      applyChord(id, fullChord);
      return;
    }

    // If this looks like a chord prefix, wait for second key
    if (isKnownPrefix(chord)) {
      capturePrefix = chord;
      capturePrefixTimer = setTimeout(() => {
        // Timeout — use the prefix as a single-key chord
        if (capturePrefix) {
          applyChord(id, capturePrefix);
        }
      }, 1000);
      return;
    }

    // Single-key chord
    applyChord(id, chord);
  }

  function applyChord(id: string, chord: string) {
    // Conflict check
    const conflict = keybindingStore.bindings.find(
      (b) => b.id !== id && b.chord === chord
    );

    if (conflict) {
      conflictWarning = `Conflicts with "${conflict.label}"`;
    } else {
      conflictWarning = null;
    }

    keybindingStore.setChord(id, chord);
    clearCapture();
  }

  function resetAll() {
    keybindingStore.resetAll();
    conflictWarning = null;
  }

  function isModified(b: Keybinding): boolean {
    return b.chord !== b.defaultChord;
  }
</script>

<div class="kb-settings">
  <!-- Toolbar -->
  <div class="kb-toolbar">
    <input
      class="kb-search"
      type="search"
      placeholder="Search shortcuts\u2026"
      bind:value={searchQuery}
      aria-label="Search keyboard shortcuts"
    />
    <button class="kb-reset-all" onclick={resetAll} title="Reset all shortcuts to defaults">
      Reset All
    </button>
  </div>

  {#if conflictWarning}
    <div class="kb-conflict-banner" role="alert">
      Warning: {conflictWarning}
    </div>
  {/if}

  <!-- Table by category -->
  {#each CATEGORY_ORDER as category}
    {#if grouped[category]?.length}
      <div class="kb-category">
        <div class="kb-category-header">{category}</div>
        <div class="kb-table">
          {#each grouped[category] as binding (binding.id)}
            <div class="kb-row" class:modified={isModified(binding)}>
              <span class="kb-label">{binding.label}</span>

              <!-- Chord cell: click to capture -->
              {#if capturingId === binding.id}
                <!-- svelte-ignore a11y_no_static_element_interactions -->
                <div
                  class="kb-chord capturing"
                  tabindex="0"
                  role="button"
                  aria-label="Press new key combination for {binding.label}"
                  autofocus
                  onkeydown={(e) => handleCaptureKeydown(e, binding.id)}
                  onblur={() => clearCapture()}
                >
                  {capturePrefix ? `${capturePrefix} + \u2026` : 'Press keys\u2026'}
                </div>
              {:else}
                <button
                  class="kb-chord"
                  onclick={() => startCapture(binding.id)}
                  title="Click to rebind"
                  aria-label="Current shortcut for {binding.label}: {formatChord(binding.chord)}. Click to change."
                >
                  {formatChord(binding.chord)}
                </button>
              {/if}

              <!-- Reset button: only shown when modified -->
              {#if isModified(binding)}
                <button
                  class="kb-reset"
                  onclick={() => keybindingStore.resetChord(binding.id)}
                  title="Reset to {formatChord(binding.defaultChord)}"
                  aria-label="Reset {binding.label} to default"
                >
                  \u21A9 {formatChord(binding.defaultChord)}
                </button>
              {:else}
                <span class="kb-reset-placeholder"></span>
              {/if}
            </div>
          {/each}
        </div>
      </div>
    {/if}
  {/each}

  {#if filtered.length === 0}
    <p class="kb-empty">No shortcuts match "{searchQuery}"</p>
  {/if}
</div>

<style>
  .kb-settings { display: flex; flex-direction: column; gap: 1rem; }
  .kb-toolbar { display: flex; gap: 0.5rem; align-items: center; }
  .kb-search { flex: 1; height: 1.75rem; background: var(--ctp-surface0); border: 1px solid var(--ctp-surface1); border-radius: 0.3rem; color: var(--ctp-text); font-family: var(--ui-font-family); font-size: 0.8125rem; padding: 0 0.5rem; outline: none; }
  .kb-search:focus { border-color: var(--ctp-mauve); }
  .kb-reset-all { padding: 0.25rem 0.625rem; background: transparent; border: 1px solid var(--ctp-surface1); border-radius: 0.3rem; color: var(--ctp-subtext0); font-family: var(--ui-font-family); font-size: 0.75rem; cursor: pointer; white-space: nowrap; transition: border-color 0.12s, color 0.12s; }
  .kb-reset-all:hover { border-color: var(--ctp-red); color: var(--ctp-red); }
  .kb-conflict-banner { padding: 0.375rem 0.5rem; background: color-mix(in srgb, var(--ctp-yellow) 12%, transparent); border: 1px solid var(--ctp-yellow); border-radius: 0.3rem; color: var(--ctp-yellow); font-size: 0.75rem; }
  .kb-category { display: flex; flex-direction: column; gap: 0.25rem; }
  .kb-category-header { font-size: 0.625rem; font-weight: 700; text-transform: uppercase; letter-spacing: 0.08em; color: var(--ctp-overlay0); padding: 0 0.25rem; }
  .kb-table { display: flex; flex-direction: column; gap: 0.125rem; }
  .kb-row { display: grid; grid-template-columns: 1fr auto auto; align-items: center; gap: 0.5rem; padding: 0.25rem 0.375rem; border-radius: 0.25rem; transition: background 0.1s; }
  .kb-row:hover { background: var(--ctp-surface0); }
  .kb-row.modified { background: color-mix(in srgb, var(--ctp-mauve) 6%, transparent); }
  .kb-label { font-size: 0.8125rem; color: var(--ctp-text); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
  .kb-chord { padding: 0.125rem 0.5rem; background: var(--ctp-surface0); border: 1px solid var(--ctp-surface1); border-radius: 0.25rem; color: var(--ctp-text); font-family: var(--term-font-family); font-size: 0.75rem; cursor: pointer; transition: border-color 0.12s, background 0.12s; white-space: nowrap; }
  .kb-chord:hover:not(.capturing) { border-color: var(--ctp-mauve); background: var(--ctp-surface1); }
  .kb-chord.capturing { border-color: var(--ctp-mauve); background: color-mix(in srgb, var(--ctp-mauve) 15%, var(--ctp-surface0)); color: var(--ctp-mauve); animation: pulse-capture 0.8s ease-in-out infinite; outline: none; }
  @keyframes pulse-capture { 0%, 100% { opacity: 1; } 50% { opacity: 0.65; } }
  .kb-reset { padding: 0.125rem 0.375rem; background: transparent; border: 1px solid transparent; border-radius: 0.25rem; color: var(--ctp-overlay0); font-family: var(--ui-font-family); font-size: 0.6875rem; cursor: pointer; white-space: nowrap; transition: border-color 0.12s, color 0.12s; }
  .kb-reset:hover { border-color: var(--ctp-surface1); color: var(--ctp-subtext0); }
  .kb-reset-placeholder { width: 5rem; }
  .kb-empty { text-align: center; color: var(--ctp-overlay0); font-size: 0.8125rem; font-style: italic; padding: 2rem 0; }
</style>
