<script lang="ts">
  import { tick } from 'svelte';
  import { t } from './i18n.svelte.ts';
  import {
    toggleSettings, toggleSearch, setShowWizard,
  } from './ui-store.svelte.ts';

  interface Props {
    open: boolean;
    onClose: () => void;
  }

  let { open, onClose }: Props = $props();

  interface Command {
    id: string;
    label: string;
    description?: string;
    shortcut?: string;
    action: () => void;
  }

  // Dispatch for commands not yet handled by stores
  function dispatch(name: string) {
    window.dispatchEvent(new CustomEvent('palette-command', { detail: name }));
  }

  // Command definitions — labels resolved reactively via t()
  interface CommandDef {
    id: string;
    labelKey: string;
    descKey?: string;
    shortcut?: string;
    action: () => void;
  }

  const COMMAND_DEFS: CommandDef[] = [
    { id: 'new-terminal',    labelKey: 'palette.newTerminal',     shortcut: 'Ctrl+`',         action: () => dispatch('new-terminal') },
    { id: 'settings',        labelKey: 'palette.openSettings',    shortcut: 'Ctrl+,',         action: () => toggleSettings() },
    { id: 'search',          labelKey: 'palette.searchMessages',  shortcut: 'Ctrl+Shift+F',   action: () => toggleSearch() },
    { id: 'new-project',     labelKey: 'palette.addProject',      descKey: 'palette.addProjectDesc',   action: () => setShowWizard(true) },
    { id: 'clear-agent',     labelKey: 'palette.clearAgent',      descKey: 'palette.clearAgentDesc',   action: () => dispatch('clear-agent') },
    { id: 'copy-cost',       labelKey: 'palette.copyCost',        action: () => dispatch('copy-cost') },
    { id: 'docs',            labelKey: 'palette.openDocs',        shortcut: 'F1',             action: () => dispatch('docs') },
    { id: 'theme',           labelKey: 'palette.changeTheme',     descKey: 'palette.changeThemeDesc',  action: () => dispatch('theme') },
    { id: 'split-h',         labelKey: 'palette.splitH',          shortcut: 'Ctrl+\\',        action: () => dispatch('split-h') },
    { id: 'split-v',         labelKey: 'palette.splitV',          shortcut: 'Ctrl+Shift+\\',  action: () => dispatch('split-v') },
    { id: 'focus-next',      labelKey: 'palette.focusNext',       shortcut: 'Ctrl+Tab',       action: () => dispatch('focus-next') },
    { id: 'focus-prev',      labelKey: 'palette.focusPrev',       shortcut: 'Ctrl+Shift+Tab', action: () => dispatch('focus-prev') },
    { id: 'close-tab',       labelKey: 'palette.closeTab',        shortcut: 'Ctrl+W',         action: () => dispatch('close-tab') },
    { id: 'toggle-terminal', labelKey: 'palette.toggleTerminal',  shortcut: 'Ctrl+J',         action: () => dispatch('toggle-terminal') },
    { id: 'reload-plugins',  labelKey: 'palette.reloadPlugins',   action: () => dispatch('reload-plugins') },
    { id: 'toggle-sidebar',  labelKey: 'palette.toggleSidebar',   shortcut: 'Ctrl+B',         action: () => toggleSettings() },
    { id: 'zoom-in',         labelKey: 'palette.zoomIn',          shortcut: 'Ctrl+=',         action: () => dispatch('zoom-in') },
    { id: 'zoom-out',        labelKey: 'palette.zoomOut',         shortcut: 'Ctrl+-',         action: () => dispatch('zoom-out') },
  ];

  // Build commands once — NOT $derived (creating new array per evaluation causes loops)
  function buildCommands(): Command[] {
    return COMMAND_DEFS.map(d => ({
      id: d.id,
      label: t(d.labelKey as any),
      description: d.descKey ? t(d.descKey as any) : undefined,
      shortcut: d.shortcut,
      action: d.action,
    }));
  }
  let COMMANDS = buildCommands();

  let query = $state('');
  let selectedIdx = $state(0);
  let inputEl = $state<HTMLInputElement | undefined>(undefined);

  let filtered = $derived(
    query.trim() === ''
      ? COMMANDS
      : COMMANDS.filter(c =>
          c.label.toLowerCase().includes(query.toLowerCase()) ||
          c.description?.toLowerCase().includes(query.toLowerCase())
        )
  );

  $effect(() => {
    if (open) {
      query = '';
      selectedIdx = 0;
      tick().then(() => inputEl?.focus());
    }
  });

  // Clamp selection when query changes (NOT via $effect — avoids read+write cycle)
  function clampSelection() {
    const len = filtered.length;
    if (selectedIdx >= len) selectedIdx = Math.max(0, len - 1);
  }

  function handleKeydown(e: KeyboardEvent) {
    if (e.key === 'Escape') { onClose(); return; }
    if (e.key === 'ArrowDown') { e.preventDefault(); selectedIdx = Math.min(selectedIdx + 1, filtered.length - 1); return; }
    if (e.key === 'ArrowUp')   { e.preventDefault(); selectedIdx = Math.max(selectedIdx - 1, 0); return; }
    if (e.key === 'Enter' && filtered[selectedIdx]) {
      filtered[selectedIdx].action();
      onClose();
    }
  }

  function executeCommand(cmd: Command) {
    cmd.action();
    onClose();
  }

  function handleBackdropClick(e: MouseEvent) {
    if (e.target === e.currentTarget) onClose();
  }
</script>

<!-- Fix #11: display toggle instead of {#if} -->
<!-- svelte-ignore a11y_no_noninteractive_element_interactions -->
<div
  class="palette-backdrop"
  style:display={open ? 'flex' : 'none'}
  onclick={handleBackdropClick}
  onkeydown={handleKeydown}
  role="dialog"
  aria-modal="true"
  aria-label="Command Palette"
  tabindex="-1"
>
    <div class="palette-panel">
      <div class="palette-input-row">
        <svg class="palette-icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" aria-hidden="true">
          <circle cx="11" cy="11" r="8"/><line x1="21" y1="21" x2="16.65" y2="16.65"/>
        </svg>
        <input
          class="palette-input"
          type="text"
          role="combobox"
          placeholder={t('palette.placeholder')}
          bind:this={inputEl}
          bind:value={query}
          oninput={() => clampSelection()}
          onkeydown={handleKeydown}
          aria-label="Command search"
          aria-autocomplete="list"
          aria-expanded="true"
          aria-controls="palette-list"
          aria-activedescendant={filtered[selectedIdx] ? `cmd-${filtered[selectedIdx].id}` : undefined}
          autocomplete="off"
          spellcheck="false"
        />
        <kbd class="palette-esc-hint">Esc</kbd>
      </div>

      <ul
        id="palette-list"
        class="palette-list"
        role="listbox"
        aria-label="Commands"
      >
        {#each filtered as cmd, i (cmd.id)}
          <!-- svelte-ignore a11y_click_events_have_key_events -->
          <li
            id="cmd-{cmd.id}"
            class="palette-item"
            class:selected={i === selectedIdx}
            role="option"
            aria-selected={i === selectedIdx}
            onclick={() => executeCommand(cmd)}
            onmouseenter={() => selectedIdx = i}
          >
            <span class="cmd-label">{cmd.label}</span>
            {#if cmd.description}
              <span class="cmd-desc">{cmd.description}</span>
            {/if}
            {#if cmd.shortcut}
              <kbd class="cmd-shortcut">{cmd.shortcut}</kbd>
            {/if}
          </li>
        {/each}
        {#if filtered.length === 0}
          <li class="palette-empty" role="option" aria-selected="false">No commands found</li>
        {/if}
      </ul>
    </div>
</div>

<style>
  .palette-backdrop {
    position: fixed;
    inset: 0;
    z-index: 300;
    background: color-mix(in srgb, var(--ctp-crust) 70%, transparent);
    display: flex;
    align-items: flex-start;
    justify-content: center;
    padding-top: 6rem;
  }

  .palette-panel {
    width: 36rem;
    max-width: 92vw;
    background: var(--ctp-mantle);
    border: 1px solid var(--ctp-surface1);
    border-radius: 0.625rem;
    overflow: hidden;
    box-shadow: 0 1.25rem 3rem color-mix(in srgb, var(--ctp-crust) 60%, transparent);
    animation: palette-appear 0.12s ease-out;
  }

  @keyframes palette-appear {
    from { transform: translateY(-0.5rem) scale(0.98); opacity: 0; }
    to   { transform: translateY(0) scale(1); opacity: 1; }
  }

  /* Input row */
  .palette-input-row {
    display: flex;
    align-items: center;
    gap: 0.5rem;
    padding: 0 0.75rem;
    border-bottom: 1px solid var(--ctp-surface0);
    height: 3rem;
  }

  .palette-icon {
    width: 1rem;
    height: 1rem;
    color: var(--ctp-overlay1);
    flex-shrink: 0;
  }

  .palette-input {
    flex: 1;
    background: transparent;
    border: none;
    outline: none;
    color: var(--ctp-text);
    font-family: var(--ui-font-family);
    font-size: 0.9375rem;
    caret-color: var(--ctp-mauve);
  }

  .palette-input::placeholder { color: var(--ctp-overlay0); }

  .palette-esc-hint {
    padding: 0.15rem 0.35rem;
    background: var(--ctp-surface0);
    border: 1px solid var(--ctp-surface1);
    border-radius: 0.25rem;
    font-size: 0.6875rem;
    color: var(--ctp-overlay1);
    font-family: var(--ui-font-family);
    white-space: nowrap;
  }

  /* Command list */
  .palette-list {
    list-style: none;
    margin: 0;
    padding: 0.375rem;
    max-height: 22rem;
    overflow-y: auto;
    display: flex;
    flex-direction: column;
    gap: 0.0625rem;
  }

  .palette-list::-webkit-scrollbar { width: 0.375rem; }
  .palette-list::-webkit-scrollbar-track { background: transparent; }
  .palette-list::-webkit-scrollbar-thumb { background: var(--ctp-surface1); border-radius: 0.25rem; }

  .palette-item {
    display: flex;
    align-items: center;
    gap: 0.5rem;
    padding: 0.5rem 0.625rem;
    border-radius: 0.375rem;
    cursor: pointer;
    transition: background 0.08s;
  }

  .palette-item.selected {
    background: var(--ctp-surface0);
  }

  .palette-item:hover {
    background: var(--ctp-surface0);
  }

  .cmd-label {
    flex: 1;
    font-size: 0.875rem;
    color: var(--ctp-text);
  }

  .cmd-desc {
    font-size: 0.75rem;
    color: var(--ctp-subtext0);
    max-width: 12rem;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
  }

  .cmd-shortcut {
    padding: 0.1rem 0.3rem;
    background: var(--ctp-surface1);
    border: 1px solid var(--ctp-surface2);
    border-radius: 0.2rem;
    font-size: 0.6875rem;
    color: var(--ctp-subtext0);
    font-family: var(--ui-font-family);
    white-space: nowrap;
    flex-shrink: 0;
  }

  .palette-empty {
    padding: 1.5rem;
    text-align: center;
    font-size: 0.875rem;
    color: var(--ctp-overlay0);
    font-style: italic;
  }
</style>
