// ============================================================
// PAGERS & EXTENSIONS — personal directory with async search + soft delete
// ============================================================
  var _inited = false;
  var _items = [];
  var _mode = 'active';        // 'active' | 'trash'
  var _editId = null;           // null = creating, non-null = editing
  var _searchDebounce = null;
  var _pendingImportFile = null;

  document.addEventListener('tabChanged', function (e) {
    if (e.detail.tab !== 'extensions' || _inited) return;
    _inited = true;
    init();
  });

  function init() {
    document.getElementById('ext-add-btn').addEventListener('click', onAddClick);
    document.getElementById('ext-cancel-btn').addEventListener('click', hideForm);
    document.getElementById('ext-save-btn').addEventListener('click', saveItem);
    document.getElementById('ext-export-btn').addEventListener('click', exportItems);
    document.getElementById('ext-import-btn').addEventListener('click', function () {
      document.getElementById('ext-import-file').click();
    });
    document.getElementById('ext-import-file').addEventListener('change', importItems);
    document.getElementById('ext-import-confirm').addEventListener('click', confirmImportPreview);
    document.getElementById('ext-import-cancel').addEventListener('click', clearImportPreview);
    document.getElementById('ext-trash-btn').addEventListener('click', toggleTrashMode);
    document.getElementById('ext-back-active').addEventListener('click', function () { _mode = 'active'; updateModeBanner(); load(); });

    var searchInp = document.getElementById('ext-search');
    searchInp.addEventListener('input', function () {
      clearTimeout(_searchDebounce);
      _searchDebounce = setTimeout(load, 200);
    });

    // Keyboard: Esc cancels form
    document.addEventListener('keydown', function (e) {
      if (e.key === 'Escape' && !document.getElementById('ext-form-wrap').classList.contains('hidden')) {
        hideForm();
      }
    });

    load();
    loadTrashCount();
  }

  function loadTrashCount() {
    fetch('/api/extensions?trash=1', { headers: getAuthHeaders() })
      .then(function (r) { return r.json(); })
      .then(function (d) {
        if (d.success) {
          var n = (d.items || []).length;
          document.getElementById('ext-trash-count').textContent = n ? '(' + n + ')' : '';
        }
      })
      .catch(function () {});
  }

  function load() {
    var q = document.getElementById('ext-search').value.trim();
    var url = '/api/extensions?' + (_mode === 'trash' ? 'trash=1&' : '') + (q ? 'q=' + encodeURIComponent(q) : '');
    var listEl = document.getElementById('ext-list');
    listEl.innerHTML = '<p style="text-align:center;color:#9ca3af;padding:30px;">Loading...</p>';

    fetch(url, { headers: getAuthHeaders() })
      .then(function (r) { return r.json(); })
      .then(function (d) {
        if (!d.success) { listEl.innerHTML = '<p style="text-align:center;color:var(--red);padding:20px;">' + esc(d.error || 'Load failed') + '</p>'; return; }
        _items = d.items || [];
        render();
        refreshLocationList();
      })
      .catch(function (err) {
        listEl.innerHTML = '<p style="text-align:center;color:var(--red);padding:20px;">Load failed: ' + esc(err.message) + '</p>';
      });
  }

  function refreshLocationList() {
    // Populate datalist with existing unique locations for autocomplete
    var dl = document.getElementById('ext-location-list');
    if (!dl) return;
    var seen = {};
    var opts = [];
    _items.forEach(function (x) {
      if (!seen[x.location]) { seen[x.location] = true; opts.push(x.location); }
    });
    dl.innerHTML = opts.map(function (l) { return '<option value="' + esc(l) + '">'; }).join('');
  }

  function render() {
    var listEl = document.getElementById('ext-list');
    if (_items.length === 0) {
      var icon = _mode === 'trash' ? 'fa-trash-can' : 'fa-phone-slash';
      var msg = _mode === 'trash' ? 'Trash is empty' : 'No entries yet';
      var q = document.getElementById('ext-search').value.trim();
      if (q) { icon = 'fa-magnifying-glass'; msg = 'No matches for "' + esc(q) + '"'; }
      listEl.innerHTML =
        '<div style="text-align:center;padding:60px 20px;color:var(--g400);">' +
          '<div style="font-size:48px;margin-bottom:14px;opacity:0.4;"><i class="fas ' + icon + '"></i></div>' +
          '<div style="font-size:14px;font-weight:500;color:var(--g500);">' + msg + '</div>' +
        '</div>';
      return;
    }

    // Group by location → type
    var byLoc = {};
    _items.forEach(function (x) {
      if (!byLoc[x.location]) byLoc[x.location] = { extension: [], pager: [] };
      (byLoc[x.location][x.type] || byLoc[x.location].extension).push(x);
    });

    var html = '';
    Object.keys(byLoc).sort().forEach(function (loc) {
      html += '<div class="ext-loc-group" style="margin-bottom:18px;">';
      html += '<h3 style="font-size:14px;color:var(--g700);margin:12px 0 8px;display:flex;align-items:center;gap:8px;"><i class="fas fa-map-marker-alt" style="color:var(--g400);"></i> ' + esc(loc) + '</h3>';

      ['extension', 'pager'].forEach(function (type) {
        var arr = byLoc[loc][type];
        if (!arr || arr.length === 0) return;
        html += '<div style="margin-left:4px;">';
        html += '<div style="font-size:11px;text-transform:uppercase;letter-spacing:0.5px;color:var(--g500);font-weight:600;margin:6px 0 4px;">' + (type === 'pager' ? '📟 Pagers' : '☎️ Extensions') + '</div>';
        html += '<div style="display:grid;grid-template-columns:repeat(auto-fill,minmax(240px,1fr));gap:10px;">';
        arr.forEach(function (x, i) { html += renderCard(x, i); });
        html += '</div></div>';
      });

      html += '</div>';
    });
    listEl.innerHTML = html;

    // Wire per-card events
    listEl.querySelectorAll('[data-ext-action]').forEach(function (btn) {
      btn.addEventListener('click', function () {
        var action = btn.dataset.extAction;
        var id = parseInt(btn.dataset.extId, 10);
        if (!Number.isFinite(id) || id <= 0) return;
        if (action === 'edit')    return startEdit(id);
        if (action === 'delete')  return confirmDelete(id);
        if (action === 'restore') return restoreItem(id);
        if (action === 'purge')   return confirmPurge(id);
      });
    });

    // Click-to-copy on the number itself. Visual feedback is a brief
    // green flash via the .ext-copied class — no toast spam since the
    // user is doing this repeatedly while phoning around.
    listEl.querySelectorAll('.ext-number[data-copy]').forEach(function (btn) {
      btn.addEventListener('click', function () {
        var v = btn.dataset.copy || '';
        if (!v) return;
        var done = function () {
          btn.classList.add('ext-copied');
          setTimeout(function () { btn.classList.remove('ext-copied'); }, 600);
        };
        if (navigator.clipboard && navigator.clipboard.writeText) {
          navigator.clipboard.writeText(v).then(done).catch(function () {
            // Clipboard blocked — fall back to a textarea hack
            var ta = document.createElement('textarea');
            ta.value = v; ta.style.position = 'fixed'; ta.style.left = '-9999px';
            document.body.appendChild(ta); ta.select();
            try { document.execCommand('copy'); done(); } catch (e) {}
            document.body.removeChild(ta);
          });
        } else {
          done();
        }
      });
    });
  }

  function renderCard(x, idx) {
    var typeColor = x.type === 'pager' ? '#7c3aed' : '#2563eb';
    var typeLabel = x.type === 'pager' ? 'Pager' : 'Ext';
    var typeIcon = x.type === 'pager' ? 'fa-pager' : 'fa-phone';
    var trashed = x.trashed_at != null;
    // Alternating subtle backgrounds — every other card gets a slight
    // off-white tint so a long list reads as distinct rows instead of a
    // wall of identical white boxes. Trashed rows use their own muted bg.
    var bg = trashed
      ? '#fafaf9'
      : ((idx % 2 === 0) ? 'var(--white, #fff)' : '#fafbfc');
    var border = trashed ? 'var(--g300)' : 'var(--g200)';
    // Stagger entrance — each card delayed slightly so they appear in a
    // gentle wave instead of a single jarring pop. Capped at 12 to keep
    // long lists snappy.
    var stagger = Math.min(idx == null ? 0 : idx, 12) * 35;

    var actions;
    if (trashed) {
      actions =
        '<button class="btn-sm btn-ghost ext-action" data-ext-action="restore" data-ext-id="' + x.id + '" title="Restore"><i class="fas fa-rotate-left"></i></button>' +
        '<button class="btn-sm btn-ghost ext-action" data-ext-action="purge" data-ext-id="' + x.id + '" title="Delete permanently" style="color:var(--red);"><i class="fas fa-xmark"></i></button>';
    } else {
      actions =
        '<button class="btn-sm btn-ghost ext-action" data-ext-action="edit" data-ext-id="' + x.id + '" title="Edit"><i class="fas fa-pen"></i></button>' +
        '<button class="btn-sm btn-ghost ext-action" data-ext-action="delete" data-ext-id="' + x.id + '" title="Move to trash"><i class="fas fa-trash-can"></i></button>';
    }

    var html = '';
    // Card layout:
    //   - uniform 1px border (no left stripe — too visually bulky)
    //   - phone/pager icon + colored number = type signal
    //   - number is click-to-copy with a green flash (data-copy)
    //   - hover lift + shadow grow via .ext-card:hover in styles.css
    //   - staggered fade-in (--ext-stagger CSS var consumed by keyframes)
    html += '<div class="ext-card" style="background:' + bg + ';border:1px solid ' + border + ';border-radius:10px;padding:12px 14px;display:flex;gap:12px;align-items:flex-start;--ext-stagger:' + stagger + 'ms;">';
    html += '  <div style="flex:1;min-width:0;">';
    html += '    <div style="display:flex;align-items:baseline;gap:10px;flex-wrap:wrap;min-width:0;">';
    html += '      <i class="fas ' + typeIcon + '" style="color:' + typeColor + ';font-size:14px;align-self:center;flex-shrink:0;"></i>';
    html += '      <button type="button" class="ext-number" data-copy="' + esc(x.number) + '" title="Click to copy" style="font-size:20px;font-weight:700;color:' + typeColor + ';font-family:ui-monospace,SFMono-Regular,monospace;letter-spacing:0.5px;line-height:1.2;word-break:break-all;min-width:0;background:none;border:0;padding:0;cursor:pointer;font-feature-settings:\'tnum\' 1;text-align:left;">' + esc(x.number) + '</button>';
    html += '      <span style="font-size:10px;font-weight:600;padding:2px 7px;border-radius:6px;background:' + typeColor + '15;color:' + typeColor + ';text-transform:uppercase;letter-spacing:0.6px;flex-shrink:0;">' + typeLabel + '</span>';
    html += '    </div>';
    // Name: scan-target. Larger, bolder, darker, slightly tighter
    // letter spacing for that "headline" feel. The number is the action;
    // the name is what your eye locks onto when scrolling a list of 50.
    html += '    <div class="ext-name" style="font-size:14.5px;color:var(--g900);margin-top:6px;word-break:break-word;font-weight:700;letter-spacing:-0.012em;line-height:1.35;">' + esc(x.name) + '</div>';
    if (x.notes) html += '    <div style="font-size:11.5px;color:var(--g500);margin-top:3px;word-break:break-word;line-height:1.45;">' + esc(x.notes) + '</div>';
    html += '  </div>';
    html += '  <div style="display:flex;gap:4px;flex-shrink:0;align-self:flex-start;">' + actions + '</div>';
    html += '</div>';
    return html;
  }

  function onAddClick() {
    _editId = null;
    document.getElementById('ext-location').value = '';
    document.getElementById('ext-name').value = '';
    document.getElementById('ext-number').value = '';
    document.getElementById('ext-type').value = 'extension';
    document.getElementById('ext-notes').value = '';
    document.getElementById('ext-form-status').textContent = '';
    document.getElementById('ext-save-btn').innerHTML = '<i class="fas fa-floppy-disk"></i> Save';
    document.getElementById('ext-form-wrap').classList.remove('hidden');
    document.getElementById('ext-location').focus();
  }

  function hideForm() {
    document.getElementById('ext-form-wrap').classList.add('hidden');
    _editId = null;
  }

  function startEdit(id) {
    var item = _items.filter(function (x) { return x.id === id; })[0];
    if (!item) return;
    _editId = id;
    document.getElementById('ext-location').value = item.location;
    document.getElementById('ext-name').value = item.name;
    document.getElementById('ext-number').value = item.number;
    document.getElementById('ext-type').value = item.type;
    document.getElementById('ext-notes').value = item.notes || '';
    document.getElementById('ext-form-status').textContent = '';
    document.getElementById('ext-save-btn').innerHTML = '<i class="fas fa-check"></i> Update';
    document.getElementById('ext-form-wrap').classList.remove('hidden');
    document.getElementById('ext-location').scrollIntoView({ behavior: 'smooth', block: 'nearest' });
  }

  function saveItem() {
    var body = {
      location: document.getElementById('ext-location').value.trim(),
      name:     document.getElementById('ext-name').value.trim(),
      number:   document.getElementById('ext-number').value.trim(),
      type:     document.getElementById('ext-type').value,
      notes:    document.getElementById('ext-notes').value.trim()
    };
    if (!body.location || !body.name || !body.number) {
      document.getElementById('ext-form-status').textContent = 'Location, name, and number are required.';
      document.getElementById('ext-form-status').style.color = 'var(--red)';
      return;
    }
    var url = _editId ? ('/api/extensions/' + _editId) : '/api/extensions';
    var method = _editId ? 'PUT' : 'POST';
    document.getElementById('ext-save-btn').disabled = true;
    fetch(url, { method: method, headers: getAuthHeaders(), body: JSON.stringify(body) })
      .then(function (r) { return r.json(); })
      .then(function (d) {
        if (!d.success) { showToast(d.error || 'Save failed', 'error'); return; }
        hideForm();
        showToast(_editId ? 'Updated' : 'Added', 'success');
        load();
      })
      .catch(function () { showToast('Save failed', 'error'); })
      .finally(function () { document.getElementById('ext-save-btn').disabled = false; });
  }

  function confirmDelete(id) {
    var item = _items.filter(function (x) { return x.id === id; })[0];
    if (!item) return;
    showConfirm(
      'Move "' + item.name + ' (' + item.number + ')" to trash? You can restore it later from the trash view.',
      function () {
        fetch('/api/extensions/' + id, { method: 'DELETE', headers: getAuthHeaders() })
          .then(function (r) { return r.json(); })
          .then(function (d) {
            if (!d.success) { showToast(d.error || 'Delete failed', 'error'); return; }
            showToast('Moved to trash', 'success');
            load();
            loadTrashCount();
          })
          .catch(function () { showToast('Delete failed', 'error'); });
      },
      { confirmText: 'Move to trash' }
    );
  }

  function restoreItem(id) {
    fetch('/api/extensions/' + id + '/restore', { method: 'POST', headers: getAuthHeaders() })
      .then(function (r) { return r.json(); })
      .then(function (d) {
        if (!d.success) { showToast(d.error || 'Restore failed', 'error'); return; }
        showToast('Restored', 'success');
        load();
        loadTrashCount();
      })
      .catch(function () { showToast('Restore failed', 'error'); });
  }

  function confirmPurge(id) {
    var item = _items.filter(function (x) { return x.id === id; })[0];
    if (!item) return;
    showConfirm(
      'Permanently delete "' + item.name + ' (' + item.number + ')"? This cannot be undone.',
      function () {
        fetch('/api/extensions/' + id + '/purge', { method: 'DELETE', headers: getAuthHeaders() })
          .then(function (r) { return r.json(); })
          .then(function (d) {
            if (!d.success) { showToast(d.error || 'Delete failed', 'error'); return; }
            showToast('Permanently deleted', 'success');
            load();
            loadTrashCount();
          })
          .catch(function () { showToast('Delete failed', 'error'); });
      },
      { danger: true, confirmText: 'Delete permanently' }
    );
  }

  function exportItems() {
    fetch('/api/extensions/export', { headers: getAuthHeaders() })
      .then(function (r) {
        if (!r.ok) throw new Error('Export failed');
        var count = parseInt(r.headers.get('X-Export-Count') || '', 10);
        return r.blob().then(function (blob) { return { blob: blob, count: count }; });
      })
      .then(function (d) {
        var a = document.createElement('a');
        var stamp = new Date().toISOString().slice(0, 10);
        a.href = URL.createObjectURL(d.blob);
        a.download = 'pedscribe-extensions-' + stamp + '.zip';
        document.body.appendChild(a);
        a.click();
        URL.revokeObjectURL(a.href);
        document.body.removeChild(a);
        showToast('Exported ' + (Number.isFinite(d.count) ? d.count : 'your') + ' entries', 'success');
      })
      .catch(function () { showToast('Export failed', 'error'); });
  }

  function importItems(e) {
    var input = e.target;
    var file = input.files && input.files[0];
    if (!file) return;
    previewImportFile(file, input);
  }

  function previewImportFile(file, input) {
    var form = new FormData();
    form.append('file', file);
    var headers = getAuthHeaders();
    delete headers['Content-Type'];
    fetch('/api/extensions/import-file/preview', { method: 'POST', headers: headers, body: form })
      .then(function (r) { return r.json(); })
      .then(function (d) {
        if (!d.success) { showToast(d.error || 'Import preview failed', 'error'); input.value = ''; return; }
        _pendingImportFile = { file: file, input: input };
        renderImportPreview(d.preview && d.preview.summary);
      })
      .catch(function () { showToast('Import preview failed', 'error'); input.value = ''; });
  }

  function renderImportPreview(summary) {
    summary = summary || {};
    var panel = document.getElementById('ext-import-preview');
    var text = document.getElementById('ext-import-preview-text');
    var restore = document.getElementById('ext-import-restore-trashed');
    var possible = document.getElementById('ext-import-possible');
    restore.checked = false;
    possible.checked = false;
    restore.disabled = !summary.exactTrashed;
    possible.disabled = !summary.possible;
    text.innerHTML =
      '<strong>Import preview:</strong> ' + esc(summary.total || 0) + ' valid entries found. ' +
      esc(summary.new || 0) + ' new, ' +
      esc(summary.exactActive || 0) + ' exact active duplicates, ' +
      esc(summary.exactTrashed || 0) + ' exact matches in trash, ' +
      esc(summary.possible || 0) + ' possible duplicates by location/number or number/type. ' +
      'Exact active duplicates are always skipped.';
    panel.classList.remove('hidden');
  }

  function clearImportPreview() {
    document.getElementById('ext-import-preview').classList.add('hidden');
    if (_pendingImportFile && _pendingImportFile.input) _pendingImportFile.input.value = '';
    _pendingImportFile = null;
  }

  function confirmImportPreview() {
    if (!_pendingImportFile) return;
    submitImportFile(_pendingImportFile.file, _pendingImportFile.input, {
      restoreTrashed: document.getElementById('ext-import-restore-trashed').checked,
      importPossibleDuplicates: document.getElementById('ext-import-possible').checked
    });
  }

  function submitImportFile(file, input, options) {
    var form = new FormData();
    form.append('file', file);
    form.append('restoreTrashed', options && options.restoreTrashed ? 'true' : 'false');
    form.append('importPossibleDuplicates', options && options.importPossibleDuplicates ? 'true' : 'false');
    var headers = getAuthHeaders();
    delete headers['Content-Type'];
    fetch('/api/extensions/import-file', {
      method: 'POST',
      headers: headers,
      body: form
    })
      .then(function (r) { return r.json(); })
      .then(function (d) {
        if (!d.success) { showToast(d.error || 'Import failed', 'error'); return; }
        showToast('Imported ' + d.imported + ' entries' + (d.restored ? ', restored ' + d.restored : '') + (d.skipped ? ', skipped ' + d.skipped : ''), 'success');
        clearImportPreview();
        load();
        loadTrashCount();
      })
      .catch(function () { showToast('Import failed', 'error'); })
      .finally(function () { input.value = ''; });
  }

  function toggleTrashMode() {
    _mode = (_mode === 'trash') ? 'active' : 'trash';
    updateModeBanner();
    load();
  }
  function updateModeBanner() {
    var banner = document.getElementById('ext-mode-banner');
    var trashBtn = document.getElementById('ext-trash-btn');
    if (_mode === 'trash') {
      banner.classList.remove('hidden');
      trashBtn.innerHTML = '<i class="fas fa-list"></i> Active items';
      document.getElementById('ext-add-btn').style.display = 'none';
    } else {
      banner.classList.add('hidden');
      trashBtn.innerHTML = '<i class="fas fa-trash-can"></i> Trash <span id="ext-trash-count" style="color:var(--g500);font-size:11px;"></span>';
      document.getElementById('ext-add-btn').style.display = '';
      loadTrashCount();
    }
  }

  function esc(s) {
    if (s == null) return '';
    return String(s).replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;').replace(/"/g, '&quot;');
  }
