/* global React, ReactDOM */
const { useState, useEffect, useMemo, useRef } = React;

// =========================================================
// CommandPalette (⌘K / Ctrl+K) — fuzzy-searchable actions.
// Surfaces tweaks, widget controls, theme toggles, and quick navigation.
// Receives commands prop: [{ id, label, desc?, icon?, section?, kbd?, run }]
// =========================================================

window.CommandPalette = function CommandPalette({ commands, onClose }) {
  const [q, setQ] = useState('');
  const [active, setActive] = useState(0);
  const inputRef = useRef(null);
  const listRef = useRef(null);

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

  // Filter + group
  const filtered = useMemo(() => {
    if (!q.trim()) return commands;
    const lc = q.toLowerCase();
    return commands.filter(c => {
      const hay = `${c.label} ${c.desc || ''} ${c.section || ''}`.toLowerCase();
      return hay.includes(lc);
    });
  }, [q, commands]);

  // Group by section preserving original order
  const groups = useMemo(() => {
    const map = new Map();
    filtered.forEach(c => {
      const s = c.section || 'Akce';
      if (!map.has(s)) map.set(s, []);
      map.get(s).push(c);
    });
    return [...map.entries()];
  }, [filtered]);

  // Reset active when filter changes
  useEffect(() => { setActive(0); }, [q]);

  // Flat list for keyboard navigation
  const flat = filtered;

  useEffect(() => {
    const onKey = (e) => {
      if (e.key === 'Escape') { onClose(); return; }
      if (e.key === 'ArrowDown') {
        e.preventDefault();
        setActive(a => Math.min(flat.length - 1, a + 1));
      } else if (e.key === 'ArrowUp') {
        e.preventDefault();
        setActive(a => Math.max(0, a - 1));
      } else if (e.key === 'Enter') {
        e.preventDefault();
        const c = flat[active];
        if (c) { c.run(); onClose(); }
      }
    };
    document.addEventListener('keydown', onKey);
    return () => document.removeEventListener('keydown', onKey);
  }, [active, flat, onClose]);

  // Scroll active into view
  useEffect(() => {
    const el = listRef.current?.querySelector(`[data-idx="${active}"]`);
    if (el) {
      const r = el.getBoundingClientRect();
      const pr = listRef.current.getBoundingClientRect();
      if (r.bottom > pr.bottom) el.scrollIntoView({ block: 'nearest' });
      else if (r.top < pr.top) el.scrollIntoView({ block: 'nearest' });
    }
  }, [active]);

  let idx = 0;
  const node = (
    <div className="cmd-backdrop" onClick={(e) => { if (e.target === e.currentTarget) onClose(); }}>
      <div className="cmd-panel" role="dialog" aria-label="Příkazová paleta">
        <div className="cmd-input-row">
          <i className="bi bi-search"></i>
          <input
            ref={inputRef}
            className="cmd-input"
            type="text"
            placeholder="Hledat akci, widget, nastavení…"
            value={q}
            onChange={(e) => setQ(e.target.value)}
          />
          <span className="cmd-kbd">esc</span>
        </div>
        <div className="cmd-list" ref={listRef}>
          {groups.length === 0 && (
            <div className="cmd-section" style={{padding:'18px 14px'}}>
              Žádný výsledek pro „{q}"
            </div>
          )}
          {groups.map(([section, items]) => (
            <React.Fragment key={section}>
              <div className="cmd-section">{section}</div>
              {items.map(c => {
                const myIdx = idx++;
                return (
                  <div
                    key={c.id}
                    data-idx={myIdx}
                    className={`cmd-item ${myIdx === active ? 'active' : ''}`}
                    onMouseEnter={() => setActive(myIdx)}
                    onClick={() => { c.run(); onClose(); }}
                  >
                    {c.icon && <div className="ico"><i className={`bi bi-${c.icon}`}></i></div>}
                    <div style={{display:'flex',flexDirection:'column',minWidth:0,flex:1}}>
                      <div style={{fontWeight:500}}>{c.label}</div>
                      {c.desc && <div style={{fontSize:'calc(11px * var(--fs))',color:'var(--muted)'}}>{c.desc}</div>}
                    </div>
                    {c.kbd && <span className="kbd">{c.kbd}</span>}
                  </div>
                );
              })}
            </React.Fragment>
          ))}
        </div>
      </div>
    </div>
  );
  return ReactDOM.createPortal(node, document.body);
};

// =========================================================
// Toast — momentary status notification (used after Reset etc.)
// =========================================================
window.showToast = function (msg, opts = {}) {
  const root = document.body;
  const node = document.createElement('div');
  node.className = 'toast';
  const icon = opts.icon || 'check2-circle';
  node.innerHTML = `<i class="bi bi-${icon}" style="color:var(--accent)"></i><span></span>`;
  node.querySelector('span').textContent = msg;
  // Optional action buttons (e.g. "Vrátit" for undo after hiding a widget;
  // `actions` = several, `secondary` = quieter). Clicking dismisses the toast
  // first (so a prompt() in the handler doesn't sit on top of it), then runs it.
  const actions = (opts.actions || (opts.action ? [opts.action] : []))
    .filter(a => a && typeof a.onClick === 'function');
  actions.forEach((a) => {
    const btn = document.createElement('button');
    btn.type = 'button';
    btn.className = 'toast-action' + (a.secondary ? ' is-secondary' : '');
    btn.textContent = a.label || 'OK';
    btn.onclick = () => { node.remove(); a.onClick(); };
    node.appendChild(btn);
  });
  if (opts.close) {
    const x = document.createElement('button');
    x.type = 'button';
    x.className = 'toast-x';
    x.setAttribute('aria-label', 'Zavřít');
    x.innerHTML = '<i class="bi bi-x" aria-hidden="true"></i>';
    x.onclick = () => node.remove();
    node.appendChild(x);
  }
  if (actions.length > 1 || opts.close) node.classList.add('has-actions');
  root.appendChild(node);
  // Undo toasts get a longer fuse so the user has time to react; the fuse
  // pauses while the pointer is over the toast.
  let left = opts.duration || (actions.length ? 5000 : 1800);
  let started = 0, timer = 0;
  const hide = () => {
    node.style.transition = 'opacity .2s, transform .2s';
    node.style.opacity = '0';
    node.style.transform = 'translate(-50%, 8px)';
    setTimeout(() => node.remove(), 220);
  };
  const run = () => { started = Date.now(); timer = setTimeout(hide, Math.max(0, left)); };
  node.addEventListener('mouseenter', () => { clearTimeout(timer); left -= Date.now() - started; });
  node.addEventListener('mouseleave', run);
  run();
};
