// lib/ui.js — toasts, command palette, helpers.

const toastsEl = () => document.getElementById('toasts');

export function toast({ kind = 'info', title = '', body = '', ttl = 3800 } = {}) {
  const host = toastsEl();
  if (!host) return;
  const el = document.createElement('div');
  el.className = `toast ${kind}`;
  el.innerHTML = `<div class="ttl"></div><div class="body"></div>`;
  el.querySelector('.ttl').textContent = title || ({
    ok: 'Success', warn: 'Warning', err: 'Error', info: 'Info',
  }[kind] || 'Info');
  el.querySelector('.body').textContent = body || '';
  host.appendChild(el);
  setTimeout(() => {
    el.style.opacity = '0';
    el.style.transform = 'translateY(8px)';
    el.style.transition = 'all 200ms';
    setTimeout(() => el.remove(), 220);
  }, ttl);
}

export const ok   = (body, title) => toast({ kind: 'ok',   body, title });
export const warn = (body, title) => toast({ kind: 'warn', body, title });
export const err  = (body, title) => toast({ kind: 'err',  body, title });

// ---------- Command palette ----------
const paletteCommands = [];
let paletteOpen = false;
let paletteFiltered = [];
let paletteIndex = 0;

export function registerCommand(cmd) {
  // cmd: { id, label, group, run(), keywords?: string }
  paletteCommands.push(cmd);
}

function renderPalette() {
  const list = document.getElementById('palette-list');
  if (!list) return;
  list.innerHTML = paletteFiltered.map((c, i) => `
    <li class="${i === paletteIndex ? 'active' : ''}" data-i="${i}">
      <svg class="ic" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><polyline points="9 18 15 12 9 6"/></svg>
      <span class="grow">${escapeHtml(c.label)}</span>
      <span class="group">${escapeHtml(c.group || '')}</span>
    </li>
  `).join('');
  list.querySelectorAll('li').forEach(li => {
    li.addEventListener('click', () => {
      const idx = parseInt(li.dataset.i, 10);
      if (!Number.isNaN(idx)) runFiltered(idx);
    });
  });
}

function filterPalette(q) {
  q = (q || '').trim().toLowerCase();
  if (!q) paletteFiltered = paletteCommands.slice(0, 30);
  else {
    paletteFiltered = paletteCommands.filter(c => {
      const hay = (c.label + ' ' + (c.group || '') + ' ' + (c.keywords || '')).toLowerCase();
      return hay.includes(q);
    }).slice(0, 40);
  }
  paletteIndex = 0;
  renderPalette();
}

function runFiltered(i) {
  const c = paletteFiltered[i];
  if (!c) return;
  closePalette();
  try { c.run(); } catch (e) { err(String(e)); }
}

export function openPalette(prefill = '') {
  const bg = document.getElementById('palette-bg');
  const inp = document.getElementById('palette-input');
  if (!bg || !inp) return;
  paletteOpen = true;
  bg.classList.add('open');
  bg.setAttribute('aria-hidden', 'false');
  inp.value = prefill;
  filterPalette(prefill);
  setTimeout(() => inp.focus(), 10);
}
export function closePalette() {
  const bg = document.getElementById('palette-bg');
  if (!bg) return;
  paletteOpen = false;
  bg.classList.remove('open');
  bg.setAttribute('aria-hidden', 'true');
}

export function initPalette() {
  const trigger = document.getElementById('cmd-trigger');
  const bg = document.getElementById('palette-bg');
  const inp = document.getElementById('palette-input');
  if (!trigger || !bg || !inp) return;
  trigger.addEventListener('click', () => openPalette());
  bg.addEventListener('click', (e) => { if (e.target === bg) closePalette(); });
  inp.addEventListener('input', (e) => filterPalette(e.target.value));
  inp.addEventListener('keydown', (e) => {
    if (e.key === 'Escape') return closePalette();
    if (e.key === 'ArrowDown') { e.preventDefault(); paletteIndex = Math.min(paletteFiltered.length - 1, paletteIndex + 1); renderPalette(); }
    if (e.key === 'ArrowUp')   { e.preventDefault(); paletteIndex = Math.max(0, paletteIndex - 1); renderPalette(); }
    if (e.key === 'Enter')     { e.preventDefault(); runFiltered(paletteIndex); }
  });
  window.addEventListener('keydown', (e) => {
    const k = (e.key || '').toLowerCase();
    if ((e.metaKey || e.ctrlKey) && k === 'k') { e.preventDefault(); paletteOpen ? closePalette() : openPalette(); }
    if (paletteOpen && e.key === 'Escape') closePalette();
  });
}

// ---------- helpers ----------
export function escapeHtml(s) {
  return String(s ?? '').replace(/[&<>"']/g, c => ({
    '&': '&amp;', '<': '&lt;', '>': '&gt;', '"': '&quot;', "'": '&#39;'
  }[c]));
}

export function skeleton(lines = 3) {
  return Array.from({ length: lines }).map((_, i) =>
    `<div class="skel" style="height: ${i === 0 ? 18 : 12}px; width: ${100 - i * 12}%; margin-top: ${i ? 8 : 0}px;"></div>`
  ).join('');
}

export function fmtJSON(v) {
  if (v == null) return '';
  if (typeof v === 'string') return v;
  try { return JSON.stringify(v, null, 2); } catch { return String(v); }
}

export function setHealthPill(state, text) {
  const pill = document.getElementById('health-pill');
  const txt  = document.getElementById('health-text');
  if (!pill || !txt) return;
  pill.classList.remove('ok', 'warn', 'err', 'info', 'muted');
  pill.classList.add(state || 'muted');
  txt.textContent = text || state || '—';
}

export function setBrandVer(text) {
  const el = document.getElementById('brand-ver');
  if (el) el.textContent = text || '—';
}
export function setFooterBuild(text) {
  const el = document.getElementById('footer-build');
  if (el) el.textContent = text || 'build —';
}
