import React, { useCallback, useEffect, useMemo, useRef, useState } from 'react';
import { createPortal } from 'react-dom';
import type { CBNode } from '../types';
import type { EditorStore } from '../store/editorStore';

// ─────────────────────────────────────────────────────────────────────────────
// Types
// ─────────────────────────────────────────────────────────────────────────────

type Category = 'all' | 'pages' | 'elements' | 'commands' | 'settings';

interface PageResult     { kind: 'page';     id: number; title: string; link: string; }
interface ElemResult     { kind: 'element';  id: string; nodeType: string; text: string; }
interface CmdResult      { kind: 'command';  id: string; label: string; icon: React.ReactNode; shortcut?: string; action: () => void; }
interface SettResult     { kind: 'setting';  id: string; label: string; icon: React.ReactNode; meta?: string; action: () => void; }

type AnyResult = PageResult | ElemResult | CmdResult | SettResult;

const CATS: { id: Category; label: string }[] = [
  { id: 'all',      label: 'All'      },
  { id: 'pages',    label: 'Pages'    },
  { id: 'elements', label: 'Elements' },
  { id: 'commands', label: 'Commands' },
  { id: 'settings', label: 'Settings' },
];

const isMac = typeof navigator !== 'undefined' && /Mac|iPhone|iPad/.test(navigator.platform);
const mod   = isMac ? '⌘' : 'Ctrl+';

// ─────────────────────────────────────────────────────────────────────────────
// Node helpers
// ─────────────────────────────────────────────────────────────────────────────

const NODE_NAMES: Record<string, string> = {
  section: 'Section', container: 'Container', column: 'Column',
  heading: 'Heading', text: 'Text', image: 'Image', button: 'Button',
  spacer: 'Spacer', divider: 'Divider', icon: 'Icon', video: 'Video',
  maps: 'Map', html: 'HTML', shortcode: 'Shortcode', logo: 'Logo',
  form: 'Form', alert: 'Alert', counter: 'Counter', progress: 'Progress',
  testimonial: 'Testimonial', accordion: 'Accordion',
};
const cap = (s: string) => NODE_NAMES[s] ?? s.charAt(0).toUpperCase() + s.slice(1);

function nodeText(n: CBNode): string {
  const c = n.content as Record<string, unknown> | undefined;
  const raw = String(c?.text ?? c?.html ?? '').replace(/<[^>]*>/g, '').trim();
  return raw.slice(0, 60) + (raw.length > 60 ? '…' : '');
}

function extractElements(sections: CBNode[]): ElemResult[] {
  const results: ElemResult[] = [];
  function walk(nodes: CBNode[]) {
    for (const n of nodes) {
      results.push({ kind: 'element', id: n.id, nodeType: n.type, text: nodeText(n) });
      if (n.children?.length) walk(n.children);
    }
  }
  walk(sections);
  return results;
}

// ─────────────────────────────────────────────────────────────────────────────
// Small SVG icon components
// ─────────────────────────────────────────────────────────────────────────────

const Ic = {
  Page: () => <svg width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round"><path d="M14.5 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V7.5L14.5 2z"/><polyline points="14 2 14 8 20 8"/></svg>,
  Grid: () => <svg width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round"><rect x="3" y="3" width="7" height="7" rx="1"/><rect x="14" y="3" width="7" height="7" rx="1"/><rect x="3" y="14" width="7" height="7" rx="1"/><rect x="14" y="14" width="7" height="7" rx="1"/></svg>,
  Heading: () => <svg width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round"><path d="M4 6h16M4 12h16M4 18h7"/></svg>,
  Text: () => <svg width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round"><path d="M4 6h16M4 10h16M4 14h16M4 18h10"/></svg>,
  Image: () => <svg width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round"><rect x="3" y="3" width="18" height="18" rx="2"/><circle cx="8.5" cy="8.5" r="1.5"/><polyline points="21 15 16 10 5 21"/></svg>,
  Btn: () => <svg width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round"><rect x="3" y="8" width="18" height="8" rx="4"/></svg>,
  Section: () => <svg width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round"><rect x="2" y="3" width="20" height="18" rx="2"/><line x1="2" y1="9" x2="22" y2="9"/></svg>,
  Box: () => <svg width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round"><rect x="2" y="5" width="20" height="14" rx="2"/></svg>,
  Video: () => <svg width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round"><rect x="2" y="3" width="15" height="15" rx="2"/><polygon points="22 7 16 12 22 17 22 7"/></svg>,
  Star: () => <svg width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round"><polygon points="12 2 15.09 8.26 22 9.27 17 14.14 18.18 21.02 12 17.77 5.82 21.02 7 14.14 2 9.27 8.91 8.26 12 2"/></svg>,
  Desktop: () => <svg width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round"><rect x="2" y="3" width="20" height="14" rx="2"/><path d="M8 21h8M12 17v4"/></svg>,
  Tablet: () => <svg width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round"><rect x="5" y="2" width="14" height="20" rx="2"/><line x1="12" y1="18" x2="12.01" y2="18"/></svg>,
  Mobile: () => <svg width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round"><rect x="7" y="2" width="10" height="20" rx="2"/><line x1="12" y1="18" x2="12.01" y2="18"/></svg>,
  Layers: () => <svg width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round"><path d="M12 2L2 7l10 5 10-5-10-5zM2 17l10 5 10-5M2 12l10 5 10-5"/></svg>,
  ZoomIn: () => <svg width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round"><circle cx="11" cy="11" r="8"/><path d="m21 21-4.35-4.35M11 8v6M8 11h6"/></svg>,
  ZoomOut: () => <svg width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round"><circle cx="11" cy="11" r="8"/><path d="m21 21-4.35-4.35M8 11h6"/></svg>,
  Save: () => <svg width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round"><path d="M19 21H5a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h11l5 5v11a2 2 0 0 1-2 2z"/><polyline points="17 21 17 13 7 13 7 21"/><polyline points="7 3 7 8 15 8"/></svg>,
  Clock: () => <svg width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round"><circle cx="12" cy="12" r="10"/><polyline points="12 6 12 12 16 14"/></svg>,
  Tpl: () => <svg width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round"><path d="M19 21H5a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h11l5 5v11a2 2 0 0 1-2 2z"/><polyline points="17 21 17 13 7 13 7 21"/></svg>,
  Undo: () => <svg width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round"><path d="M3 7v6h6"/><path d="M3 13A9 9 0 1 0 5.4 6.5"/></svg>,
  Redo: () => <svg width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round"><path d="M21 7v6h-6"/><path d="M21 13A9 9 0 1 1 18.6 6.5"/></svg>,
  Copy: () => <svg width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round"><rect x="9" y="9" width="13" height="13" rx="2"/><path d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1"/></svg>,
  Trash: () => <svg width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round"><polyline points="3 6 5 6 21 6"/><path d="M19 6l-1 14a2 2 0 0 1-2 2H8a2 2 0 0 1-2-2L5 6"/><path d="M10 11v6M14 11v6"/></svg>,
};

const NODE_ICON: Record<string, React.ReactElement> = {
  heading: <Ic.Heading />, text: <Ic.Text />, image: <Ic.Image />, button: <Ic.Btn />,
  section: <Ic.Section />, container: <Ic.Box />, column: <Ic.Box />, video: <Ic.Video />,
  icon: <Ic.Star />,
};
const getNodeIcon = (type: string) => NODE_ICON[type] ?? <Ic.Box />;

// ─────────────────────────────────────────────────────────────────────────────
// Props
// ─────────────────────────────────────────────────────────────────────────────

interface Props {
  store: EditorStore;
  api: {
    searchPages: (q: string) => Promise<Array<{ id: number; title: string; link: string }>>;
  };
  onClose:         () => void;
  onOpenRevisions: () => void;
}

// ─────────────────────────────────────────────────────────────────────────────
// Component
// ─────────────────────────────────────────────────────────────────────────────

export function GlobalFinder({ store, api, onClose, onOpenRevisions }: Props) {
  const [query,    setQuery]    = useState('');
  const [cat,      setCat]      = useState<Category>('all');
  const [focusIdx, setFocusIdx] = useState(0);

  // Async
  const [pageRes,  setPageRes]  = useState<PageResult[]>([]);
  const [pgLoad,   setPgLoad]   = useState(false);

  const inputRef    = useRef<HTMLInputElement>(null);
  const searchTimer = useRef<ReturnType<typeof setTimeout> | null>(null);

  useEffect(() => { setTimeout(() => inputRef.current?.focus(), 20); }, []);

  useEffect(() => {
    const h = (e: KeyboardEvent) => { if (e.key === 'Escape') onClose(); };
    document.addEventListener('keydown', h);
    return () => document.removeEventListener('keydown', h);
  }, [onClose]);

  // Debounced API search
  useEffect(() => {
    if (searchTimer.current) clearTimeout(searchTimer.current);
    const q = query.trim();
    if (!q) { setPageRes([]); return; }

    searchTimer.current = setTimeout(() => {
      if (cat === 'all' || cat === 'pages') {
        setPgLoad(true);
        api.searchPages(q)
          .then(p => setPageRes(p.map(r => ({ kind: 'page' as const, ...r }))))
          .catch(() => setPageRes([]))
          .finally(() => setPgLoad(false));
      }
    }, 280);

    return () => { if (searchTimer.current) clearTimeout(searchTimer.current); };
  }, [query, cat]);

  const { state } = store;

  // Sync: page elements
  const allElems = useMemo(() => extractElements(state.pageData.sections ?? []), [state.pageData]);
  const elemRes  = useMemo<ElemResult[]>(() => {
    const q = query.trim().toLowerCase();
    if (!q) return allElems.slice(0, 8);
    return allElems
      .filter(e => cap(e.nodeType).toLowerCase().includes(q) || e.text.toLowerCase().includes(q))
      .slice(0, 8);
  }, [allElems, query]);

  // Sync: commands
  const cmdRes = useMemo<CmdResult[]>(() => {
    const q = query.trim().toLowerCase();
    const all: CmdResult[] = [
      { kind: 'command', id: 'undo',      label: 'Undo',            icon: <Ic.Undo />,  shortcut: `${mod}Z`, action: () => { store.undo(); onClose(); } },
      { kind: 'command', id: 'redo',      label: 'Redo',            icon: <Ic.Redo />,  shortcut: `${mod}Y`, action: () => { store.redo(); onClose(); } },
      { kind: 'command', id: 'copy',      label: 'Copy',            icon: <Ic.Copy />,  shortcut: `${mod}C`, action: () => { if (state.selectedId) store.copyNode(state.selectedId); onClose(); } },
      { kind: 'command', id: 'paste',     label: 'Paste',           icon: <Ic.Copy />,  shortcut: `${mod}V`, action: () => { if (state.selectedId) store.pasteNode(state.selectedId); onClose(); } },
      { kind: 'command', id: 'dup',       label: 'Duplicate',       icon: <Ic.Copy />,  shortcut: `${mod}D`, action: () => { if (state.selectedId) store.duplicateNode(state.selectedId); onClose(); } },
      { kind: 'command', id: 'del',       label: 'Delete selected', icon: <Ic.Trash />, shortcut: 'Del',     action: () => { if (state.selectedId) store.deleteNode(state.selectedId); onClose(); } },
      { kind: 'command', id: 'save',      label: 'Save page',      icon: <Ic.Save />,  shortcut: `${mod}S`, action: () => { window.dispatchEvent(new CustomEvent('cb:save')); onClose(); } },
      { kind: 'command', id: 'revisions', label: 'View revisions', icon: <Ic.Clock />,                       action: () => { onOpenRevisions(); onClose(); } },
    ];
    return q ? all.filter(c => c.label.toLowerCase().includes(q)) : all;
  }, [query, store, state.selectedId, onClose, onOpenRevisions]);

  // Sync: settings
  const setRes = useMemo<SettResult[]>(() => {
    const q    = query.trim().toLowerCase();
    const { breakpoint, zoom, showLayers } = state;
    const all: SettResult[] = [
      { kind: 'setting', id: 'bp-d', label: 'Switch to Desktop view', icon: <Ic.Desktop />, meta: breakpoint === 'desktop' ? 'active' : undefined, action: () => { store.setBreakpoint('desktop'); onClose(); } },
      { kind: 'setting', id: 'bp-t', label: 'Switch to Tablet view',  icon: <Ic.Tablet />,  meta: breakpoint === 'tablet'  ? 'active' : undefined, action: () => { store.setBreakpoint('tablet');  onClose(); } },
      { kind: 'setting', id: 'bp-m', label: 'Switch to Mobile view',  icon: <Ic.Mobile />,  meta: breakpoint === 'mobile'  ? 'active' : undefined, action: () => { store.setBreakpoint('mobile');  onClose(); } },
      { kind: 'setting', id: 'z100',  label: 'Zoom to 100%',          icon: <Ic.ZoomIn />,  meta: zoom === 100 ? 'active' : `${zoom}%`,            action: () => { store.setZoom(100); onClose(); } },
      { kind: 'setting', id: 'z75',   label: 'Zoom to 75%',           icon: <Ic.ZoomOut />, meta: zoom === 75  ? 'active' : undefined,              action: () => { store.setZoom(75);  onClose(); } },
      { kind: 'setting', id: 'z125',  label: 'Zoom to 125%',          icon: <Ic.ZoomIn />,  meta: zoom === 125 ? 'active' : undefined,              action: () => { store.setZoom(125); onClose(); } },
      { kind: 'setting', id: 'layers', label: `${showLayers ? 'Hide' : 'Show'} layers panel`, icon: <Ic.Layers />, meta: showLayers ? 'visible' : 'hidden', action: () => { store.toggleLayers(); onClose(); } },
    ];
    return q ? all.filter(s => s.label.toLowerCase().includes(q)) : all;
  }, [query, state, store, onClose]);

  // ── Build sectioned view ──────────────────────────────────────────────────

  type Section = { title: string; items: AnyResult[]; loading?: boolean };

  const sections = useMemo<Section[]>(() => {
    const MAX_ALL = 4;
    const MAX_CAT = 12;
    const max = cat === 'all' ? MAX_ALL : MAX_CAT;
    const out: Section[] = [];
    const q = query.trim();

    if ((cat === 'all' || cat === 'pages') && (q || cat === 'pages'))
      out.push({ title: 'Pages', items: pageRes.slice(0, max), loading: pgLoad && !!q });

    if (cat === 'all' || cat === 'elements')
      out.push({ title: 'Page Elements', items: elemRes.slice(0, max) });

    if (cat === 'all' || cat === 'commands')
      out.push({ title: 'Commands', items: cmdRes.slice(0, max) });

    if (cat === 'all' || cat === 'settings')
      out.push({ title: 'Settings', items: setRes.slice(0, max) });

    return out.filter(s => s.items.length > 0 || s.loading);
  }, [cat, query, pageRes, elemRes, cmdRes, setRes, pgLoad]);

  const flat  = useMemo(() => sections.flatMap(s => s.items), [sections]);
  const total = flat.length;

  useEffect(() => { setFocusIdx(0); }, [query, cat]);

  // ── Execute ───────────────────────────────────────────────────────────────

  const execute = useCallback((item: AnyResult) => {
    switch (item.kind) {
      case 'page':    window.open(item.link, '_blank'); onClose(); break;
      case 'element': store.selectNode(item.id); onClose(); break;
      case 'command': item.action(); break;
      case 'setting': item.action(); break;
    }
  }, [store, onClose]);

  // ── Keyboard ──────────────────────────────────────────────────────────────

  const onKey = (e: React.KeyboardEvent<HTMLInputElement>) => {
    if (e.key === 'ArrowDown') { e.preventDefault(); setFocusIdx(i => Math.min(i + 1, total - 1)); }
    if (e.key === 'ArrowUp')   { e.preventDefault(); setFocusIdx(i => Math.max(i - 1, 0)); }
    if (e.key === 'Enter' && flat[focusIdx]) { e.preventDefault(); execute(flat[focusIdx]); }
    if (e.key === 'Tab') {
      e.preventDefault();
      const idx = CATS.findIndex(c => c.id === cat);
      setCat(CATS[(idx + 1) % CATS.length].id);
    }
  };

  // ─────────────────────────────────────────────────────────────────────────
  // Render
  // ─────────────────────────────────────────────────────────────────────────

  let gi = 0; // global index counter for keyboard focus

  return createPortal(
    <div className="jalpi-finder-backdrop" onClick={e => { if (e.target === e.currentTarget) onClose(); }}>
      <div className="jalpi-finder" role="dialog" aria-label="Global Finder">

        {/* Search */}
        <div className="jalpi-finder__search-bar">
          <svg className="jalpi-finder__search-ic" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round">
            <circle cx="11" cy="11" r="8"/><path d="m21 21-4.35-4.35"/>
          </svg>
          <input
            ref={inputRef}
            className="jalpi-finder__input"
            placeholder="Search pages, elements, commands…"
            value={query}
            onChange={e => setQuery(e.target.value)}
            onKeyDown={onKey}
            autoComplete="off"
            spellCheck={false}
          />
          {query && (
            <button className="jalpi-finder__clear" onClick={() => { setQuery(''); inputRef.current?.focus(); }} tabIndex={-1}>
              <svg width="11" height="11" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2.5" strokeLinecap="round">
                <line x1="18" y1="6" x2="6" y2="18"/><line x1="6" y1="6" x2="18" y2="18"/>
              </svg>
            </button>
          )}
          <kbd className="jalpi-finder__close-hint">Esc</kbd>
        </div>

        {/* Category tabs */}
        <div className="jalpi-finder__tabs" role="tablist">
          {CATS.map(c => (
            <button
              key={c.id}
              role="tab"
              aria-selected={cat === c.id}
              className={`jalpi-finder__tab${cat === c.id ? ' is-active' : ''}`}
              onClick={() => setCat(c.id)}
              tabIndex={-1}
            >
              {c.label}
            </button>
          ))}
        </div>

        {/* Results */}
        <div className="jalpi-finder__results">
          {sections.length === 0 && !pgLoad && (
            <div className="jalpi-finder__empty">
              {query.trim() ? (
                <>
                  <svg width="28" height="28" viewBox="0 0 24 24" fill="none" stroke="#d1d5db" strokeWidth="1.5" strokeLinecap="round">
                    <circle cx="11" cy="11" r="8"/><path d="m21 21-4.35-4.35"/>
                  </svg>
                  <span>No results for <strong>"{query}"</strong></span>
                </>
              ) : (
                <span>Type to search across pages and elements</span>
              )}
            </div>
          )}

          {sections.map(section => (
            <div key={section.title} className="jalpi-finder__section">
              <div className="jalpi-finder__section-label">{section.title}</div>

              {section.loading && (
                <div className="jalpi-finder__loading">
                  <svg className="jalpi-rev-spin" width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2.5">
                    <path d="M21 12a9 9 0 1 1-6.219-8.56"/>
                  </svg>
                  Searching…
                </div>
              )}

              {section.items.map(item => {
                const myIdx = gi++;
                const isFocused = myIdx === focusIdx;
                return (
                  <button
                    key={itemKey(item)}
                    className={`jalpi-finder__item${isFocused ? ' is-focused' : ''}`}
                    onClick={() => execute(item)}
                    onMouseEnter={() => setFocusIdx(myIdx)}
                    tabIndex={-1}
                  >
                    <span className="jalpi-finder__item-icon">{itemIcon(item)}</span>
                    <span className="jalpi-finder__item-body">
                      <span className="jalpi-finder__item-label">{itemLabel(item)}</span>
                      {itemMeta(item) && (
                        <span className="jalpi-finder__item-meta">{itemMeta(item)}</span>
                      )}
                    </span>
                    {itemBadge(item) && (
                      <kbd className="jalpi-finder__item-badge">{itemBadge(item)}</kbd>
                    )}
                    {item.kind === 'setting' && item.meta === 'active' && (
                      <span className="jalpi-finder__item-active">●</span>
                    )}
                  </button>
                );
              })}
            </div>
          ))}
        </div>

        {/* Footer */}
        <div className="jalpi-finder__footer">
          <span><kbd>↑↓</kbd> navigate</span>
          <span><kbd>↵</kbd> select</span>
          <span><kbd>Tab</kbd> category</span>
          <span className="jalpi-finder__footer-sep" />
          <span className="jalpi-finder__shortcut-hint">{mod}P to toggle</span>
        </div>
      </div>
    </div>,
    document.body
  );
}

// ─────────────────────────────────────────────────────────────────────────────
// Item helpers
// ─────────────────────────────────────────────────────────────────────────────

function itemKey(item: AnyResult): string {
  switch (item.kind) {
    case 'page':    return `page-${item.id}`;
    case 'element': return `el-${item.id}`;
    case 'command': return `cmd-${item.id}`;
    case 'setting': return `set-${item.id}`;
  }
}

function itemIcon(item: AnyResult): React.ReactNode {
  switch (item.kind) {
    case 'page':    return <Ic.Page />;
    case 'element': return getNodeIcon(item.nodeType);
    case 'command': return item.icon;
    case 'setting': return item.icon;
  }
}

function itemLabel(item: AnyResult): string {
  switch (item.kind) {
    case 'page':    return item.title;
    case 'element': return cap(item.nodeType);
    case 'command': return item.label;
    case 'setting': return item.label;
  }
}

function itemMeta(item: AnyResult): string | null {
  switch (item.kind) {
    case 'element': return item.text || null;
    case 'page':    return null;
    case 'command': return null;
    case 'setting': return item.meta && item.meta !== 'active' ? item.meta : null;
  }
}

function itemBadge(item: AnyResult): string | null {
  return item.kind === 'command' && item.shortcut ? item.shortcut : null;
}
