/* ═══════════════════════════════════════════════════════════════════
   API Helpers + Utilities
   ═══════════════════════════════════════════════════════════════════ */
function toast(msg) {
  const t = document.getElementById('toast');
  t.textContent = msg;
  t.classList.add('show');
  setTimeout(() => t.classList.remove('show'), 2200);
}

async function apiFetch(url, options) {
  try {
    const res = await fetch(url, options);
    const j = await res.json();
    if (!j.success) throw new Error(j.error || '请求失败');
    return j.data;
  } catch (e) {
    toast('错误: ' + e.message);
    throw e;
  }
}

function formatDate(dateStr) {
  if (!dateStr) return '';
  const d = new Date(dateStr);
  return d.getFullYear() + '-' + String(d.getMonth() + 1).padStart(2, '0') + '-' + String(d.getDate()).padStart(2, '0') +
    ' ' + String(d.getHours()).padStart(2, '0') + ':' + String(d.getMinutes()).padStart(2, '0');
}

function formatFileSize(bytes) {
  if (bytes < 1024) return bytes + ' B';
  if (bytes < 1048576) return (bytes / 1024).toFixed(1) + ' KB';
  return (bytes / 1048576).toFixed(1) + ' MB';
}

function escHtml(s) { const d = document.createElement('div'); d.textContent = s; return d.innerHTML; }

function escRegex(s) {
  return s.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
}
