// ============================================================
// ADMIN.JS — Admin panel: users, settings, stats
// ============================================================

function adminEscapeHtml(str) {
  if (!str) return '';
  return String(str).replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;').replace(/"/g, '&quot;').replace(/'/g, '&#39;');
}

function adminTableMessage(colspan, color, text) {
  return '<tr><td colspan="' + colspan + '" style="text-align:center;color:' + color + ';padding:20px;">' + adminEscapeHtml(text) + '</td></tr>';
}

function adminSetButtonText(btn, text, disabled) {
  if (!btn) return;
  btn.textContent = text;
  btn.disabled = !!disabled;
}

function adminSetButtonHtml(btn, html, disabled) {
  if (!btn) return;
  btn.innerHTML = html;
  btn.disabled = !!disabled;
}

function adminFlashButtonBackground(btn, color) {
  if (!btn) return;
  btn.style.background = color || '';
  setTimeout(function() { if (btn) btn.style.background = ''; }, 2000);
}

{

  let loaded = false;

  // Load admin panel when admin tab is activated
  document.addEventListener('tabChanged', function(e) {
    if (e.detail && e.detail.tab === 'admin') {
      if (!loaded) { loadAdmin(); loaded = true; }
    }
  });

  document.addEventListener('click', function(e) {
    // Refresh button
    if (e.target.closest('#btn-refresh-users')) {
      loadUsers();
    }
    // Toggle registration
    if (e.target.closest('#btn-toggle-reg')) {
      toggleRegistration();
    }
  });

  function loadAdmin() {
    loadSettings();
    loadUsers();
    // loadOidcConfig() is registered in the CMS IIFE below — it's not in scope here
  }

  // ---- SETTINGS + STATS ----

  function loadSettings() {
    fetch('/api/admin/settings', { headers: getAuthHeaders() })
      .then(function(r) { return r.json(); })
      .then(function(data) {
        if (!data.success) return;
        var stats = data.stats || {};
        var settings = data.settings || {};

        var el = document.getElementById('stat-users');
        if (el) el.textContent = stats.totalUsers !== undefined ? stats.totalUsers : '—';
        el = document.getElementById('stat-api-total');
        if (el) el.textContent = stats.totalApiCalls !== undefined ? stats.totalApiCalls : '—';
        el = document.getElementById('stat-api-today');
        if (el) el.textContent = stats.todayApiCalls !== undefined ? stats.todayApiCalls : '—';

        updateRegStatus(settings.registrationEnabled !== false);
      })
      .catch(function(err) { console.error('[Admin] Settings load failed:', err); });
  }

  function updateRegStatus(enabled) {
    var text = document.getElementById('reg-status-text');
    var btn = document.getElementById('btn-toggle-reg');
    if (text) {
      text.innerHTML = 'Registration is currently <strong style="color:' + (enabled ? 'var(--green)' : 'var(--red)') + '">' + (enabled ? '✅ Enabled' : '❌ Disabled') + '</strong>';
    }
    if (btn) btn.textContent = enabled ? 'Disable Registration' : 'Enable Registration';
    window._adminRegEnabled = enabled;
  }

  function toggleRegistration() {
    var newVal = !window._adminRegEnabled;
    fetch('/api/admin/settings/registration', {
      method: 'POST',
      headers: getAuthHeaders(),
      body: JSON.stringify({ enabled: newVal })
    })
    .then(function(r) { return r.json(); })
    .then(function(data) {
      if (data.success) {
        updateRegStatus(newVal);
        showToast('Registration ' + (newVal ? 'enabled' : 'disabled'), 'success');
      } else {
        showToast(data.error || 'Failed', 'error');
      }
    })
    .catch(function() { showToast('Request failed', 'error'); });
  }

  // ---- USERS ----

  function loadUsers() {
    var tbody = document.getElementById('admin-users-body');
    if (!tbody) return;
    tbody.innerHTML = adminTableMessage(5, 'var(--g400)', 'Loading...');

    fetch('/api/admin/users', { headers: getAuthHeaders() })
      .then(function(r) { return r.json(); })
      .then(function(data) {
        if (!data.success) { tbody.innerHTML = adminTableMessage(5, 'var(--red)', 'Failed to load users'); return; }
        renderUsers(data.users || []);
      })
      .catch(function() { tbody.innerHTML = adminTableMessage(5, 'var(--red)', 'Request failed'); });
  }

  function renderUsers(users) {
    var tbody = document.getElementById('admin-users-body');
    if (!tbody) return;

    var currentUser = JSON.parse(localStorage.getItem('ped_scribe_user') || '{}');

    if (users.length === 0) {
      tbody.innerHTML = adminTableMessage(5, 'var(--g400)', 'No users found');
      return;
    }

    tbody.innerHTML = users.map(function(u) {
      var isSelf = currentUser.id && u.id === currentUser.id;
      var roleColor = u.role === 'admin' ? 'var(--blue)' : u.role === 'moderator' ? 'var(--purple)' : 'var(--g500)';
      var statusColor = u.disabled ? 'var(--red)' : (u.email_verified ? 'var(--green)' : 'var(--amber)');
      var statusText = u.disabled ? 'Disabled' : (u.email_verified ? 'Active' : 'Unverified');
      var joined = u.created_at ? new Date(u.created_at).toLocaleDateString() : '—';

      var actions = [];
      if (!isSelf) {
        if (!u.email_verified) {
          actions.push('<button class="btn-sm btn-primary admin-action" data-action="verify" data-id="' + u.id + '" data-email="' + esc(u.email) + '">Verify</button>');
        }
        if (u.disabled) {
          actions.push('<button class="btn-sm btn-success admin-action" data-action="enable" data-id="' + u.id + '" data-email="' + esc(u.email) + '">Enable</button>');
        } else {
          actions.push('<button class="btn-sm btn-ghost admin-action" data-action="disable" data-id="' + u.id + '" data-email="' + esc(u.email) + '">Disable</button>');
        }
        if (u.role === 'admin') {
          actions.push('<button class="btn-sm btn-ghost admin-action" data-action="demote" data-id="' + u.id + '" data-email="' + esc(u.email) + '">Demote</button>');
        } else {
          actions.push('<button class="btn-sm btn-primary admin-action" data-action="promote" data-id="' + u.id + '" data-email="' + esc(u.email) + '">Make Admin</button>');
        }
        if (u.role !== 'moderator') {
          actions.push('<button class="btn-sm btn-ghost admin-action" data-action="set-moderator" data-id="' + u.id + '" data-email="' + esc(u.email) + '" style="color:var(--purple);">Set Moderator</button>');
        }
        if (u.role === 'moderator') {
          actions.push('<button class="btn-sm btn-ghost admin-action" data-action="set-user" data-id="' + u.id + '" data-email="' + esc(u.email) + '">Set User</button>');
        }
        actions.push('<button class="btn-sm btn-ghost admin-action" data-action="reset-pw" data-id="' + u.id + '" data-email="' + esc(u.email) + '">Reset PW</button>');
        actions.push('<button class="btn-sm admin-action" style="background:var(--red-light);color:var(--red);" data-action="delete" data-id="' + u.id + '" data-email="' + esc(u.email) + '" data-name="' + esc(u.name) + '">Delete</button>');
      } else {
        actions.push('<span style="font-size:12px;color:var(--g400);">(you)</span>');
      }

      return '<tr>' +
        '<td><div style="font-weight:600;font-size:13px;">' + esc(u.name) + '</div><div style="font-size:11px;color:var(--g500);">' + esc(u.email) + '</div></td>' +
        '<td><span style="font-size:12px;font-weight:600;color:' + roleColor + ';">' + (u.role || 'user') + '</span></td>' +
        '<td><span style="font-size:12px;color:' + statusColor + ';">' + statusText + '</span></td>' +
        '<td style="font-size:12px;color:var(--g500);">' + joined + '</td>' +
        '<td style="white-space:nowrap;">' + actions.join(' ') + '</td>' +
        '</tr>';
    }).join('');

    // Bind action buttons
    tbody.querySelectorAll('.admin-action').forEach(function(btn) {
      btn.addEventListener('click', function() {
        handleUserAction(btn.dataset.action, btn.dataset.id, btn.dataset.email, btn.dataset.name);
      });
    });
  }

  function handleUserAction(action, userId, email, name) {
    switch (action) {

      case 'verify':
        showConfirm('Verify email for ' + email + '?', function() {
          adminPost('/api/admin/users/' + userId + '/verify', {}, function() {
            showToast(email + ' verified', 'success'); loadUsers();
          });
        });
        break;

      case 'disable':
        showConfirm('Disable account for ' + email + '?', function() {
          adminPost('/api/admin/users/' + userId + '/disable', {}, function() {
            showToast(email + ' disabled', 'info'); loadUsers();
          });
        }, { danger: true, confirmText: 'Disable' });
        break;

      case 'enable':
        adminPost('/api/admin/users/' + userId + '/enable', {}, function() {
          showToast(email + ' enabled', 'success'); loadUsers();
        });
        break;

      case 'promote':
        showConfirm('Grant admin role to ' + email + '?', function() {
          adminPost('/api/admin/users/' + userId + '/role', { role: 'admin' }, function() {
            showToast(email + ' is now admin', 'success'); loadUsers();
          });
        });
        break;

      case 'demote':
        showConfirm('Remove admin role from ' + email + '?', function() {
          adminPost('/api/admin/users/' + userId + '/role', { role: 'user' }, function() {
            showToast(email + ' demoted to user', 'info'); loadUsers();
          });
        });
        break;

      case 'set-moderator':
        showConfirm('Set ' + email + ' as moderator? They will be able to manage Learning Hub content.', function() {
          adminPost('/api/admin/users/' + userId + '/role', { role: 'moderator' }, function() {
            showToast(email + ' is now a moderator', 'success'); loadUsers();
          });
        });
        break;

      case 'set-user':
        showConfirm('Set ' + email + ' to regular user role?', function() {
          adminPost('/api/admin/users/' + userId + '/role', { role: 'user' }, function() {
            showToast(email + ' is now a user', 'success'); loadUsers();
          });
        });
        break;

      case 'reset-pw':
        showConfirm('New password for ' + email + ' (8+ characters):', function(val) {
          if (val.length < 8) { showToast('Password must be 8+ characters', 'error'); return; }
          adminPost('/api/admin/users/' + userId + '/reset-password', { newPassword: val }, function() {
            showToast('Password reset for ' + email, 'success');
          });
        }, { input: true, inputType: 'password', placeholder: 'New password', required: true, requiredMsg: 'Enter a password', confirmText: 'Reset Password' });
        break;

      case 'delete':
        showConfirm('Permanently delete user ' + (name || email) + '? This cannot be undone.', function() {
          fetch('/api/admin/users/' + userId, { method: 'DELETE', headers: getAuthHeaders() })
            .then(function(r) { return r.json(); })
            .then(function(data) {
              if (data.success) { showToast(email + ' deleted', 'info'); loadUsers(); }
              else showToast(data.error || 'Delete failed', 'error');
            })
            .catch(function() { showToast('Request failed', 'error'); });
        }, { danger: true, confirmText: 'Delete' });
        break;
    }
  }

  function adminPost(url, body, onSuccess) {
    fetch(url, {
      method: 'POST',
      headers: getAuthHeaders(),
      body: JSON.stringify(body)
    })
    .then(function(r) { return r.json(); })
    .then(function(data) {
      if (data.success) { onSuccess(data); }
      else showToast(data.error || 'Request failed', 'error');
    })
    .catch(function() { showToast('Request failed', 'error'); });
  }

  const esc = adminEscapeHtml;

}

// ============================================================
// ADMIN CMS — Announcements, Feature Flags, Email, AI Prompts
// ============================================================
{

  let cmsLoaded = false;

  // Load CMS when admin tab is opened (via tabChanged event or click)
  document.addEventListener('tabChanged', function(e) {
    if (e.detail && e.detail.tab === 'admin') {
      if (!cmsLoaded) { loadCms(); loadOidcConfig(); cmsLoaded = true; }
    }
  });

  document.addEventListener('click', function(e) {

    // Save buttons
    if (e.target.closest('#btn-save-announcement'))  saveAnnouncement();
    if (e.target.closest('#btn-save-flags'))         saveFlags();
    if (e.target.closest('#btn-save-email'))         saveEmail();
    if (e.target.closest('#btn-test-email'))         sendTestEmail();
    if (e.target.closest('#btn-save-prompt'))        savePrompt();
    if (e.target.closest('#btn-reset-prompt'))       resetPrompt();
    if (e.target.closest('#btn-save-smtp'))          saveSmtp();
    if (e.target.closest('#btn-clear-smtp'))         clearSmtp();
    if (e.target.closest('#btn-save-auto-delete'))   saveAutoDelete();
    if (e.target.closest('#btn-reset-all-defaults')) resetAllDefaults();
  });

  // When email template selector changes, repopulate fields
  document.addEventListener('change', function(e) {
    if (e.target.id === 'cms-email-template') loadEmailFields(e.target.value);
    if (e.target.id === 'cms-prompt-select')  loadPromptText(e.target.value);
  });

  // ---- LOAD ALL CONFIG ----

  function loadCms() {
    fetch('/api/admin/config', { headers: getAuthHeaders() })
      .then(function(r) { return r.json(); })
      .then(function(data) {
        if (!data.success) return;
        var cfg = {};
        (data.config || []).forEach(function(row) { cfg[row.key] = row.value; });

        // Announcement
        var annEnabled = document.getElementById('cms-ann-enabled');
        var annType    = document.getElementById('cms-ann-type');
        var annText    = document.getElementById('cms-ann-text');
        if (annEnabled) annEnabled.value = cfg['announcement.enabled'] || 'false';
        if (annType)    annType.value    = cfg['announcement.type']    || 'info';
        if (annText)    annText.value    = cfg['announcement.text']    || '';

        // Feature flags
        var flagReadAloud = document.getElementById('cms-flag-read-aloud');
        var flagNextcloud = document.getElementById('cms-flag-nextcloud');
        if (flagReadAloud) flagReadAloud.value = cfg['feature.read_aloud'] !== undefined ? cfg['feature.read_aloud'] : 'true';
        if (flagNextcloud) flagNextcloud.value = cfg['feature.nextcloud']  !== undefined ? cfg['feature.nextcloud']  : 'true';

        // Auto-delete setting
        var autoDeleteDays = cfg['site.auto_delete_days'] || '7';
        var el = document.getElementById('cms-auto-delete-days');
        if (el) el.value = autoDeleteDays;
        el = document.getElementById('admin-auto-delete-days');
        if (el) el.textContent = autoDeleteDays;

        // Email — load verify template by default
        window._adminEmailConfig = cfg;
        loadEmailFields('verify');
      })
      .catch(function(err) { console.error('[AdminCMS] Config load failed:', err); });

    loadPromptList();
    loadSmtp();
  }

  // ---- ANNOUNCEMENT ----

  function saveAnnouncement() {
    var enabled = document.getElementById('cms-ann-enabled').value;
    var type    = document.getElementById('cms-ann-type').value;
    var text    = document.getElementById('cms-ann-text').value;

    Promise.all([
      putConfig('announcement.enabled', enabled),
      putConfig('announcement.type',    type),
      putConfig('announcement.text',    text)
    ]).then(function() {
      showToast('Announcement saved', 'success');
      if (typeof loadAnnouncement === 'function') loadAnnouncement();
    }).catch(function() { showToast('Save failed', 'error'); });
  }

  // ---- FEATURE FLAGS ----

  function saveFlags() {
    var readAloud = document.getElementById('cms-flag-read-aloud').value;
    var nextcloud = document.getElementById('cms-flag-nextcloud').value;

    Promise.all([
      putConfig('feature.read_aloud', readAloud),
      putConfig('feature.nextcloud',  nextcloud)
    ]).then(function() {
      showToast('Feature flags saved', 'success');
    }).catch(function() { showToast('Save failed', 'error'); });
  }

  // ---- EMAIL TEMPLATES ----

  function loadEmailFields(template) {
    var cfg = window._adminEmailConfig || {};
    var subject = document.getElementById('cms-email-subject');
    var body    = document.getElementById('cms-email-body');
    if (subject) subject.value = cfg['email.' + template + '.subject'] || '';
    if (body)    body.value    = cfg['email.' + template + '.body']    || '';
  }

  function saveEmail() {
    var template = document.getElementById('cms-email-template').value;
    var subject  = document.getElementById('cms-email-subject').value;
    var body     = document.getElementById('cms-email-body').value;

    Promise.all([
      putConfig('email.' + template + '.subject', subject),
      putConfig('email.' + template + '.body',    body)
    ]).then(function() {
      // Update local cache
      if (!window._adminEmailConfig) window._adminEmailConfig = {};
      window._adminEmailConfig['email.' + template + '.subject'] = subject;
      window._adminEmailConfig['email.' + template + '.body']    = body;
      showToast('Email template saved', 'success');
    }).catch(function() { showToast('Save failed', 'error'); });
  }

  function sendTestEmail() {
    var template = document.getElementById('cms-email-template').value;
    var sendBtn = document.getElementById('btn-test-email');
    // Show inline email input instead of prompt()
    var existing = document.getElementById('admin-test-email-row');
    if (existing) { existing.remove(); return; }
    var row = document.createElement('div');
    row.id = 'admin-test-email-row';
    row.style.cssText = 'margin-top:8px;display:flex;gap:6px;align-items:center;';
    row.innerHTML = '<input type="email" id="admin-test-email-input" placeholder="recipient@example.com" style="padding:5px 8px;border:1px solid var(--g300);border-radius:6px;font-size:12px;width:220px;">'
      + '<button class="btn-sm btn-primary" id="admin-test-email-submit" style="font-size:11px;">Send</button>'
      + '<button class="btn-sm btn-ghost" id="admin-test-email-cancel" style="font-size:11px;">Cancel</button>';
    if (sendBtn) sendBtn.parentElement.appendChild(row);
    document.getElementById('admin-test-email-input').focus();
    document.getElementById('admin-test-email-submit').onclick = function() {
      var to = document.getElementById('admin-test-email-input').value.trim();
      if (!to) { showToast('Enter an email address', 'error'); return; }
      fetch('/api/admin/config/test-email', {
        method: 'POST',
        headers: getAuthHeaders(),
        body: JSON.stringify({ to: to, template: template })
      })
      .then(function(r) { return r.json(); })
      .then(function(data) {
        if (data.success) { showToast('Test email sent to ' + to, 'success'); row.remove(); }
        else showToast(data.error || 'Send failed', 'error');
      })
      .catch(function() { showToast('Request failed', 'error'); });
    };
    document.getElementById('admin-test-email-cancel').onclick = function() { row.remove(); };
  }

  // ---- AI PROMPTS ----

  // ---- OIDC / SSO CONFIG ----
  function loadOidcConfig() {
    // Set callback URL display
    var callbackEl = document.getElementById('oidc-callback-url');
    if (callbackEl) callbackEl.textContent = window.location.origin + '/api/auth/oidc/callback';

    fetch('/api/auth/oidc/config', { headers: getAuthHeaders() })
      .then(function(r) { return r.json(); })
      .then(function(data) {
        if (!data.success) return;
        var c = data.config || {};
        var el;
        el = document.getElementById('oidc-enabled'); if (el) el.value = c['oidc.enabled'] || 'false';
        el = document.getElementById('oidc-issuer'); if (el) el.value = c['oidc.issuer'] || '';
        el = document.getElementById('oidc-client-id'); if (el) el.value = c['oidc.client_id'] || '';
        el = document.getElementById('oidc-client-secret'); if (el) el.placeholder = c['oidc.client_secret'] ? c['oidc.client_secret'] : 'Enter client secret';
        el = document.getElementById('oidc-button-label'); if (el) el.value = c['oidc.button_label'] || '';
        el = document.getElementById('oidc-disable-local'); if (el) el.value = c['oidc.disable_local_auth'] || 'false';
      })
      .catch(function() {});
  }

  document.addEventListener('click', function(e) {
    if (e.target.id === 'btn-save-oidc' || e.target.closest('#btn-save-oidc')) {
      e.preventDefault();
      var status = document.getElementById('oidc-save-status');
      if (status) { status.textContent = 'Saving...'; status.style.color = 'var(--g500)'; }

      var body = {
        'oidc.enabled': document.getElementById('oidc-enabled').value,
        'oidc.issuer': document.getElementById('oidc-issuer').value.trim(),
        'oidc.client_id': document.getElementById('oidc-client-id').value.trim(),
        'oidc.button_label': document.getElementById('oidc-button-label').value.trim(),
        'oidc.disable_local_auth': document.getElementById('oidc-disable-local').value
      };
      // Only send secret if user typed a new one
      var secretEl = document.getElementById('oidc-client-secret');
      if (secretEl && secretEl.value) body['oidc.client_secret'] = secretEl.value;

      fetch('/api/auth/oidc/config', {
        method: 'PUT',
        headers: getAuthHeaders(),
        body: JSON.stringify(body)
      })
      .then(function(r) { return r.json(); })
      .then(function(data) {
        if (data.success) {
          showToast('OIDC settings saved', 'success');
          if (status) status.textContent = '';
          if (secretEl) secretEl.value = '';
          loadOidcConfig();
        } else {
          showToast(data.error || 'Save failed', 'error');
          if (status) status.textContent = '';
        }
      })
      .catch(function() { showToast('Save failed', 'error'); if (status) status.textContent = ''; });
    }
  });

  function loadPromptList() {
    fetch('/api/admin/config/prompts', { headers: getAuthHeaders() })
      .then(function(r) { return r.json(); })
      .then(function(data) {
        if (!data.success) return;
        var sel = document.getElementById('cms-prompt-select');
        if (!sel) return;
        sel.innerHTML = '';
        (data.prompts || []).forEach(function(p) {
          var opt = document.createElement('option');
          opt.value = p.key;
          opt.textContent = p.key;
          sel.appendChild(opt);
        });
        window._adminPrompts = {};
        (data.prompts || []).forEach(function(p) { window._adminPrompts[p.key] = p.value; });
        if (data.prompts && data.prompts.length > 0) {
          loadPromptText(data.prompts[0].key);
        }
      })
      .catch(function(err) { console.error('[AdminCMS] Prompts load failed:', err); });
  }

  function loadPromptText(key) {
    var textarea = document.getElementById('cms-prompt-text');
    if (!textarea) return;
    textarea.value = (window._adminPrompts && window._adminPrompts[key]) || '';
  }

  function savePrompt() {
    var sel  = document.getElementById('cms-prompt-select');
    var text = document.getElementById('cms-prompt-text');
    if (!sel || !text) return;
    var key   = sel.value;
    var value = text.value;
    if (!key) return;

    putConfig('prompt.' + key, value)
      .then(function() {
        if (!window._adminPrompts) window._adminPrompts = {};
        window._adminPrompts[key] = value;
        showToast('Prompt saved', 'success');
      })
      .catch(function() { showToast('Save failed', 'error'); });
  }

  function resetPrompt() {
    var sel = document.getElementById('cms-prompt-select');
    if (!sel || !sel.value) return;
    var key = sel.value;
    showConfirm('Reset "' + key + '" to the hardcoded default? This cannot be undone.', function() {
      fetch('/api/admin/config/prompts/' + key + '/reset', {
        method: 'POST',
        headers: getAuthHeaders()
      })
      .then(function(r) { return r.json(); })
      .then(function(data) {
        if (data.success) {
          if (!window._adminPrompts) window._adminPrompts = {};
          window._adminPrompts[key] = data.value;
          var textarea = document.getElementById('cms-prompt-text');
          if (textarea) textarea.value = data.value;
          showToast('Prompt reset to default', 'success');
        } else {
          showToast(data.error || 'Reset failed', 'error');
        }
      })
      .catch(function() { showToast('Request failed', 'error'); });
    });
  }

  // ---- SMTP ----

  function loadSmtp() {
    fetch('/api/admin/config/smtp/status', { headers: getAuthHeaders() })
      .then(function(r) { return r.json(); })
      .then(function(data) {
        if (!data.success) return;
        var badge = document.getElementById('smtp-source-badge');
        if (badge) {
          if (data.source === 'env') badge.textContent = 'Configured via env';
          else if (data.source === 'database') badge.textContent = 'Configured in DB';
          else { badge.textContent = 'Not configured'; badge.style.background = 'var(--red-light)'; badge.style.color = 'var(--red)'; }
        }
        var h = document.getElementById('cms-smtp-host'); if (h) h.value = data.host || '';
        var p = document.getElementById('cms-smtp-port'); if (p) p.value = data.port || '587';
        var u = document.getElementById('cms-smtp-user'); if (u) u.value = data.user || '';
        var f = document.getElementById('cms-smtp-from'); if (f) f.value = data.from || '';
      })
      .catch(function() {});
  }

  function saveSmtp() {
    var host   = document.getElementById('cms-smtp-host').value.trim();
    var port   = document.getElementById('cms-smtp-port').value.trim();
    var user   = document.getElementById('cms-smtp-user').value.trim();
    var pass   = document.getElementById('cms-smtp-pass').value.trim();
    var from   = document.getElementById('cms-smtp-from').value.trim();
    var secure = document.getElementById('cms-smtp-secure').value;
    if (!host) { showToast('SMTP host required', 'error'); return; }

    fetch('/api/admin/config/smtp', {
      method: 'PUT',
      headers: getAuthHeaders(),
      body: JSON.stringify({ host: host, port: port, user: user, pass: pass, from: from, secure: secure === 'true' })
    })
    .then(function(r) { return r.json(); })
    .then(function(data) {
      if (data.success) { showToast('SMTP settings saved', 'success'); loadSmtp(); }
      else showToast(data.error || 'Save failed', 'error');
    })
    .catch(function() { showToast('Request failed', 'error'); });
  }

  function clearSmtp() {
    showConfirm('Clear DB SMTP settings? Env vars will be used if set.', function() {
      fetch('/api/admin/config/smtp', { method: 'DELETE', headers: getAuthHeaders() })
        .then(function(r) { return r.json(); })
        .then(function(data) {
          if (data.success) { showToast('SMTP DB settings cleared', 'info'); loadSmtp(); }
          else showToast(data.error || 'Failed', 'error');
        })
        .catch(function() { showToast('Request failed', 'error'); });
    });
  }

  // ---- AUTO-DELETE / RESET ----

  function saveAutoDelete() {
    var days = document.getElementById('cms-auto-delete-days').value;
    putConfig('site.auto_delete_days', days)
      .then(function() {
        var el = document.getElementById('admin-auto-delete-days');
        if (el) el.textContent = days;
        showToast('Auto-delete set to ' + days + ' days', 'success');
      })
      .catch(function() { showToast('Save failed', 'error'); });
  }

  function resetAllDefaults() {
    showConfirm('Reset all settings to factory defaults? Announcements, feature flags, email templates will be reset. SMTP and custom models are preserved.', function() {
      fetch('/api/admin/config/reset-defaults', { method: 'POST', headers: getAuthHeaders() })
        .then(function(r) { return r.json(); })
        .then(function(data) {
          if (data.success) {
            showToast(data.message || 'Reset to defaults', 'success');
            cmsLoaded = false;
            loadCms();
          } else showToast(data.error || 'Reset failed', 'error');
        })
        .catch(function() { showToast('Request failed', 'error'); });
    }, { danger: true, confirmText: 'Reset' });
  }

  // ---- HELPERS ----

  function putConfig(key, value) {
    return fetch('/api/admin/config/' + encodeURIComponent(key), {
      method: 'PUT',
      headers: getAuthHeaders(),
      body: JSON.stringify({ value: value })
    })
    .then(function(r) { return r.json(); })
    .then(function(data) {
      if (!data.success) throw new Error(data.error || 'Failed');
      return data;
    });
  }

}

// ============================================================
// ADMIN CLINICAL ASSISTANT SETTINGS
// ============================================================
{
  let loaded = false;
  const defaults = {
    behavior: 'You are a concise pediatric clinical assistant. Use retrieved context only for factual claims. If the user input is a greeting or too vague, answer briefly and ask what they want to look up. Synthesize across sources and cite factual claims with the exact provided source numbers like [1]. Do not invent, renumber, merge, or move citations.'
  };

  document.addEventListener('tabChanged', function(e) {
    if (e.detail && e.detail.tab === 'admin') {
      if (!loaded) { loadAssistantAdmin(); loaded = true; }
    }
  });

  document.addEventListener('click', function(e) {
    if (e.target.closest('#btn-save-assistant-config')) saveAssistantAdmin();
    if (e.target.closest('#btn-test-assistant-chat-model')) testAssistantChatModel();
    if (e.target.closest('#btn-regenerate-assistant-prompt-pool')) regenerateAssistantPromptPool();
    if (e.target.closest('#btn-restore-assistant-prompt-pool')) restoreAssistantPromptPool();
    if (e.target.closest('#btn-refresh-assistant-image-models')) loadAssistantImageModels();
    if (e.target.closest('#btn-test-assistant-image-model')) testAssistantImageModel();
    if (e.target.closest('#btn-use-custom-assistant-image-model')) useCustomAssistantImageModel();
  });

  function loadAssistantAdmin() {
    Promise.all([
      fetch('/api/models', { headers: getAuthHeaders() }).then(function(r) { return r.json(); }).catch(function() { return {}; }),
      fetch('/api/admin/config', { headers: getAuthHeaders() }).then(function(r) { return r.json(); }).catch(function() { return {}; })
    ]).then(function(results) {
      var modelsData = results[0] || {};
      var configData = results[1] || {};
      var cfg = {};
      (configData.config || []).forEach(function(row) { cfg[row.key] = row.value; });

      var chatSelect = document.getElementById('assistant-chat-model');
      if (chatSelect) {
        var savedChatModel = cfg['clinical_assistant.chat_model'] || '';
        var defaultLabel = modelsData.defaultModel ? ('Use global default (' + modelsData.defaultModel + ')') : 'Use global default';
        chatSelect.innerHTML = '';
        var defaultOpt = document.createElement('option');
        defaultOpt.value = '';
        defaultOpt.textContent = defaultLabel;
        chatSelect.appendChild(defaultOpt);
        (modelsData.models || []).forEach(function(m) {
          var opt = document.createElement('option');
          opt.value = m.id;
          opt.textContent = m.name || m.id;
          chatSelect.appendChild(opt);
        });
        if (savedChatModel && !Array.prototype.some.call(chatSelect.options, function(o) { return o.value === savedChatModel; })) {
          var saved = document.createElement('option');
          saved.value = savedChatModel;
          saved.textContent = savedChatModel + ' (saved/custom)';
          chatSelect.appendChild(saved);
        }
        chatSelect.value = savedChatModel;
      }
      window._assistantImageModelValue = cfg['clinical_assistant.image_model'] || '';
      loadAssistantImageModels();
      loadAssistantPromptPoolStatus();
      setValue('assistant-search-limit', cfg['clinical_assistant.search_limit'] || '8');
      setValue('assistant-context-chars', cfg['clinical_assistant.context_chars'] || '1400');
      setValue('assistant-system-behavior', cfg['clinical_assistant.system_behavior'] || defaults.behavior);
    });
  }

  function loadAssistantImageModels() {
    var sel = document.getElementById('assistant-image-model');
    if (!sel) return;
    var current = sel.value || window._assistantImageModelValue || '';
    sel.innerHTML = '<option value="">Loading image models...</option>';
    fetch('/api/admin/config/image-models/discover', { headers: getAuthHeaders() })
      .then(function(r) { return r.json(); })
      .then(function(data) {
        sel.innerHTML = '<option value="">Use default (openai-gpt-image-1)</option>';
        (data.models || []).forEach(function(m) {
          var opt = document.createElement('option');
          opt.value = m.id;
          opt.textContent = m.name || m.id;
          sel.appendChild(opt);
        });
        if (current) {
          if (!Array.prototype.some.call(sel.options, function(o) { return o.value === current; })) {
            var custom = document.createElement('option');
            custom.value = current;
            custom.textContent = current + ' (saved/custom)';
            sel.appendChild(custom);
          }
          sel.value = current;
        }
      })
      .catch(function() {
        sel.innerHTML = '<option value="">Use default (openai-gpt-image-1)</option>';
        ['openai-gpt-image-1', 'openai-gpt-image-1-mini', 'openai-gpt-image-1.5', 'openai-dall-e-3'].forEach(function(id) {
          var opt = document.createElement('option'); opt.value = id; opt.textContent = id; sel.appendChild(opt);
        });
        if (current) sel.value = current;
      });
  }

  function testAssistantChatModel() {
    var model = getValue('assistant-chat-model');
    var result = document.getElementById('assistant-chat-test-result');
    if (!model) {
      var select = document.getElementById('assistant-chat-model');
      var selected = select && select.options[select.selectedIndex] ? select.options[select.selectedIndex].textContent : 'global default';
      if (result) result.textContent = 'Testing ' + selected + '...';
    } else if (result) {
      result.textContent = 'Testing ' + model + '...';
    }
    fetch('/api/admin/config/models/test', {
      method: 'POST', headers: getAuthHeaders(), body: JSON.stringify({ modelId: model || getGlobalDefaultFromAssistantSelect() })
    }).then(function(r) { return r.json(); }).then(function(data) {
      if (!data.success) throw new Error(data.error || 'Chat model test failed');
      if (result) result.textContent = 'Chat model OK (' + data.duration + ' ms): ' + (data.response || '').trim();
      showToast('Chat model works', 'success');
    }).catch(function(err) {
      if (result) result.textContent = err.message;
      showToast(err.message, 'error');
    });
  }

  function getGlobalDefaultFromAssistantSelect() {
    var select = document.getElementById('assistant-chat-model');
    if (!select || !select.options[0]) return '';
    var match = select.options[0].textContent.match(/\((.+)\)$/);
    return match ? match[1] : '';
  }

  function loadAssistantPromptPoolStatus() {
    var result = document.getElementById('assistant-prompt-pool-status');
    if (result) result.textContent = 'Checking prompt pool...';
    fetch('/api/admin/clinical-assistant/prompt-pool', { headers: getAuthHeaders() })
      .then(function(r) { return r.json(); })
      .then(function(data) {
        if (!data.success) throw new Error(data.error || 'Prompt pool status failed');
        renderAssistantPromptPoolStatus(data.meta);
        renderAssistantPromptPoolSnapshots(data.snapshots || []);
      })
      .catch(function(err) {
        if (result) result.textContent = err.message;
      });
  }

  function regenerateAssistantPromptPool() {
    var result = document.getElementById('assistant-prompt-pool-status');
    var btn = document.getElementById('btn-regenerate-assistant-prompt-pool');
    if (btn) btn.disabled = true;
    if (result) result.textContent = 'Regenerating prompt pool. This can take several minutes...';
    fetch('/api/admin/clinical-assistant/prompt-pool/regenerate', {
      method: 'POST', headers: getAuthHeaders(), body: JSON.stringify({})
    }).then(function(r) { return r.json(); }).then(function(data) {
      if (!data.success) throw new Error(data.error || 'Prompt pool regeneration failed');
      renderAssistantPromptPoolStatus(data.meta || { count: data.count, generatedAt: Date.now() });
      renderAssistantPromptPoolSnapshots(data.snapshots || []);
      showToast('Prompt pool regenerated', 'success');
    }).catch(function(err) {
      if (result) result.textContent = err.message;
      showToast(err.message, 'error');
    }).finally(function() {
      if (btn) btn.disabled = false;
    });
  }

  function renderAssistantPromptPoolStatus(meta) {
    var result = document.getElementById('assistant-prompt-pool-status');
    if (!result) return;
    if (!meta) {
      result.textContent = 'No generated pool found. The assistant will use indexed-topic fallback until you generate one.';
      return;
    }
    var generated = meta.generatedAt ? new Date(meta.generatedAt).toLocaleString() : 'unknown time';
    result.textContent = 'Generated pool: ' + (meta.count || 0) + ' prompts, target ' + (meta.target || '?') + ', generated ' + generated + (meta.restoredFrom ? ', restored from snapshot #' + meta.restoredFrom : '') + '.';
  }

  function renderAssistantPromptPoolSnapshots(snapshots) {
    var select = document.getElementById('assistant-prompt-pool-snapshots');
    if (!select) return;
    select.innerHTML = '';
    if (!snapshots.length) {
      var empty = document.createElement('option');
      empty.value = '';
      empty.textContent = 'No saved snapshots';
      select.appendChild(empty);
      return;
    }
    snapshots.forEach(function(s) {
      var opt = document.createElement('option');
      opt.value = s.id;
      var date = s.created_at ? new Date(s.created_at).toLocaleString() : 'unknown time';
      opt.textContent = '#' + s.id + ' - ' + (s.count || 0) + ' prompts - ' + date + (s.restored_from ? ' (restored from #' + s.restored_from + ')' : '');
      select.appendChild(opt);
    });
  }

  function restoreAssistantPromptPool() {
    var select = document.getElementById('assistant-prompt-pool-snapshots');
    var id = select ? select.value : '';
    var result = document.getElementById('assistant-prompt-pool-status');
    if (!id) { showToast('Select a prompt pool snapshot', 'error'); return; }
    if (result) result.textContent = 'Restoring prompt pool snapshot #' + id + '...';
    fetch('/api/admin/clinical-assistant/prompt-pool/restore', {
      method: 'POST', headers: getAuthHeaders(), body: JSON.stringify({ id: Number(id) })
    }).then(function(r) { return r.json(); }).then(function(data) {
      if (!data.success) throw new Error(data.error || 'Prompt pool restore failed');
      renderAssistantPromptPoolStatus(data.meta || { count: data.count, generatedAt: Date.now(), restoredFrom: id });
      renderAssistantPromptPoolSnapshots(data.snapshots || []);
      showToast('Prompt pool restored', 'success');
    }).catch(function(err) {
      if (result) result.textContent = err.message;
      showToast(err.message, 'error');
    });
  }

  function testAssistantImageModel() {
    var model = getValue('assistant-image-model') || 'openai-gpt-image-1';
    var result = document.getElementById('assistant-image-test-result');
    if (result) result.innerHTML = '<i class="fas fa-spinner fa-spin"></i> Testing ' + escAssistant(model) + '...';
    fetch('/api/admin/config/image-models/test', {
      method: 'POST', headers: getAuthHeaders(), body: JSON.stringify({ modelId: model })
    }).then(function(r) { return r.json(); }).then(function(data) {
      if (!data.success) throw new Error(data.error || 'Image test failed');
      var src = data.imageUrl || (data.base64 ? ('data:image/png;base64,' + data.base64) : '');
      if (result) result.innerHTML = 'Image model OK (' + data.duration + ' ms)' + (src ? '<div style="margin-top:8px;"><img src="' + escAssistant(src) + '" alt="test image" style="max-width:180px;border:1px solid var(--g200);border-radius:8px;"></div>' : '');
      showToast('Image model works', 'success');
    }).catch(function(err) {
      if (result) result.textContent = err.message;
      showToast(err.message, 'error');
    });
  }

  function useCustomAssistantImageModel() {
    var input = document.getElementById('assistant-custom-image-model');
    var sel = document.getElementById('assistant-image-model');
    var model = input ? input.value.trim() : '';
    if (!model) { showToast('Enter an image model ID', 'error'); return; }
    if (sel && !Array.prototype.some.call(sel.options, function(o) { return o.value === model; })) {
      var opt = document.createElement('option');
      opt.value = model;
      opt.textContent = model + ' (custom)';
      sel.appendChild(opt);
    }
    if (sel) sel.value = model;
    window._assistantImageModelValue = model;
    showToast('Custom image model selected. Save settings to keep it.', 'info');
  }

  function saveAssistantAdmin() {
    var status = document.getElementById('assistant-admin-status');
    if (status) status.textContent = 'Saving...';
    Promise.all([
      putAssistantConfig('clinical_assistant.chat_model', getValue('assistant-chat-model')),
      putAssistantConfig('clinical_assistant.image_model', getValue('assistant-image-model')),
      putAssistantConfig('clinical_assistant.search_limit', getValue('assistant-search-limit') || '8'),
      putAssistantConfig('clinical_assistant.context_chars', getValue('assistant-context-chars') || '1400'),
      putAssistantConfig('clinical_assistant.system_behavior', getValue('assistant-system-behavior') || defaults.behavior)
    ]).then(function() {
      if (status) status.textContent = '';
      showToast('Assistant settings saved', 'success');
    }).catch(function(err) {
      if (status) status.textContent = '';
      showToast(err.message || 'Save failed', 'error');
    });
  }

  function putAssistantConfig(key, value) {
    return fetch('/api/admin/config/' + encodeURIComponent(key), {
      method: 'PUT', headers: getAuthHeaders(), body: JSON.stringify({ value: value })
    }).then(function(r) { return r.json(); }).then(function(data) {
      if (!data.success) throw new Error(data.error || 'Save failed');
      return data;
    });
  }
  function getValue(id) { var el = document.getElementById(id); return el ? el.value.trim() : ''; }
  function setValue(id, value) { var el = document.getElementById(id); if (el) el.value = value; }
  const escAssistant = adminEscapeHtml;
}

// ============================================================
// ADMIN MODEL MANAGEMENT — Discover, search, enable/disable, custom models
// ============================================================
{

  document.addEventListener('tabChanged', function(e) {
    if (e.detail && e.detail.tab === 'admin') {
      loadAdminModels();
    }
  });

  document.addEventListener('click', function(e) {
    if (e.target.closest('#btn-discover-models'))    discoverModels();
    if (e.target.closest('#btn-add-custom-model'))   addCustomModel();
    if (e.target.closest('#btn-save-default-model')) saveDefaultModel();
    if (e.target.closest('#btn-clear-all-models'))   clearAllModels();
    if (e.target.closest('.admin-model-test-btn')) {
      var btn = e.target.closest('.admin-model-test-btn');
      testModel(btn.dataset.mid, btn);
    }
  });

  // Allow Enter key to trigger search
  document.addEventListener('keydown', function(e) {
    if (e.target.id === 'admin-model-search' && e.key === 'Enter') {
      e.preventDefault();
      discoverModels();
    }
  });

  const esc = adminEscapeHtml;

  function loadAdminModels() {
    fetch('/api/admin/config/models', { headers: getAuthHeaders() })
      .then(function(r) { return r.json(); })
      .then(function(data) {
        if (!data.success) return;

        // Provider badge
        var badge = document.getElementById('admin-model-provider-badge');
        if (badge) badge.textContent = (data.provider || 'unknown').toUpperCase();

        // Default model selector — built-ins + custom models
        var defaultSel = document.getElementById('admin-default-model');
        if (defaultSel) {
          defaultSel.innerHTML = '';
          data.models.forEach(function(m) {
            var opt = document.createElement('option');
            opt.value = m.id;
            opt.textContent = m.name + (m.enabled === false ? ' (disabled)' : '');
            defaultSel.appendChild(opt);
          });
          (data.custom || []).forEach(function(m) {
            var opt = document.createElement('option');
            opt.value = m.id;
            opt.textContent = m.name;
            defaultSel.appendChild(opt);
          });
          // Pre-select the saved default
          if (data.defaultModel) defaultSel.value = data.defaultModel;
        }

        // Built-in models with toggle
        var container = document.getElementById('admin-builtin-models');
        if (container) {
          if (data.litellmHint) {
            container.innerHTML = '<div style="padding:10px 12px;background:var(--g50);border-radius:6px;font-size:13px;color:var(--g600);">' +
              '<p style="margin:0 0 8px;"><i class="fas fa-info-circle" style="color:var(--blue);"></i> <strong>LiteLLM mode:</strong> No built-in models. ' +
              'Use <strong>Search API</strong> below to discover models from your proxy, then add them.</p>' +
              '<button id="btn-clear-all-models" class="btn-sm" style="background:var(--red-light);color:var(--red);border:none;border-radius:6px;padding:4px 12px;font-size:12px;cursor:pointer;">' +
              '<i class="fas fa-trash"></i> Clear all added models</button></div>';
          } else if (data.models.length === 0) {
            container.innerHTML = '<p style="color:var(--g400);font-size:13px;">No built-in models for this provider.</p>';
          } else {
            container.innerHTML = data.models.map(function(m) {
              var checked = m.enabled !== false ? 'checked' : '';
              return '<div style="display:flex;align-items:center;gap:8px;padding:6px 8px;border-radius:6px;background:var(--g50);font-size:13px;">' +
                '<label style="display:flex;align-items:center;gap:8px;flex:1;cursor:pointer;margin:0;">' +
                '<input type="checkbox" class="admin-model-toggle" data-model-id="' + esc(m.id) + '" ' + checked + ' style="accent-color:var(--blue);">' +
                '<span style="flex:1;"><strong>' + esc(m.name) + '</strong> <span style="color:var(--g500);font-size:11px;">(' + esc(m.id) + ')</span></span>' +
                '<span style="font-size:11px;padding:1px 6px;border-radius:4px;background:var(--g100);color:var(--g600);">' + esc(m.tag || '') + '</span>' +
                '<span style="font-size:11px;color:var(--g500);">' + esc(m.cost || '') + '</span>' +
                '</label>' +
                '<button class="btn-sm admin-model-test-btn" data-mid="' + esc(m.id) + '" style="padding:2px 8px;font-size:11px;background:var(--g100);color:var(--g700);border:none;border-radius:4px;cursor:pointer;white-space:nowrap;">Test</button>' +
                '</div>';
            }).join('');

            container.querySelectorAll('.admin-model-toggle').forEach(function(cb) {
              cb.addEventListener('change', function() {
                toggleModel(cb.dataset.modelId, cb.checked);
              });
            });
          }
        }

        // Custom models list
        renderCustomModels(data.custom || []);
      })
      .catch(function(err) { console.error('[AdminModels] Load failed:', err); });
  }

  function toggleModel(modelId, enabled) {
    fetch('/api/admin/config/models/toggle', {
      method: 'PUT',
      headers: getAuthHeaders(),
      body: JSON.stringify({ modelId: modelId, enabled: enabled })
    })
    .then(function(r) { return r.json(); })
    .then(function(data) {
      if (data.success) {
        showToast(modelId + ' ' + (enabled ? 'enabled' : 'disabled'), 'success');
      } else {
        showToast(data.error || 'Failed', 'error');
        // Revert checkbox
        var cb = document.querySelector('.admin-model-toggle[data-model-id="' + modelId + '"]');
        if (cb) cb.checked = !enabled;
      }
    })
    .catch(function() { showToast('Request failed', 'error'); });
  }

  function discoverModels() {
    var search = (document.getElementById('admin-model-search') || {}).value || '';
    var container = document.getElementById('admin-discovered-models');
    var hint = document.getElementById('admin-discover-hint');
    if (!container) return;

    container.innerHTML = '<p style="color:var(--g400);font-size:13px;"><i class="fas fa-spinner fa-spin"></i> Querying provider API...</p>';
    if (hint) hint.style.display = 'none';

    fetch('/api/admin/config/models/discover?q=' + encodeURIComponent(search), { headers: getAuthHeaders() })
      .then(function(r) { return r.json(); })
      .then(function(data) {
        if (!data.success) {
          container.innerHTML = '<p style="color:var(--red);font-size:13px;">Error: ' + esc(data.error || 'Unknown error') + '</p>';
          return;
        }
        if (!data.models || data.models.length === 0) {
          container.innerHTML = '<p style="color:var(--g400);font-size:13px;">No models found' + (search ? ' matching "' + esc(search) + '"' : '') + '. Try a different search term.</p>';
          return;
        }

        container.innerHTML = '<p style="font-size:12px;color:var(--g500);margin:0 0 6px;">Found ' + data.count + ' models. Click + to add to your model list.</p>' +
          data.models.slice(0, 100).map(function(m) {
            return '<div style="display:flex;align-items:center;gap:8px;padding:5px 8px;border-radius:6px;background:var(--g50);font-size:13px;">' +
              '<button class="btn-sm btn-primary admin-add-discovered" data-mid="' + esc(m.id) + '" data-mname="' + esc(m.name) + '" data-mcost="' + esc(m.cost) + '" data-mcat="' + esc(m.category) + '" style="padding:2px 8px;font-size:11px;min-width:28px;">+</button>' +
              '<button class="btn-sm admin-model-test-btn" data-mid="' + esc(m.id) + '" style="padding:2px 8px;font-size:11px;background:var(--g100);color:var(--g700);border:none;border-radius:4px;cursor:pointer;">Test</button>' +
              '<span style="flex:1;"><strong>' + esc(m.name) + '</strong> <span style="color:var(--g500);font-size:11px;">(' + esc(m.id) + ')</span></span>' +
              '<span style="font-size:11px;color:var(--g500);">' + esc(m.cost || '') + '</span>' +
              '<span style="font-size:10px;padding:1px 5px;border-radius:3px;background:var(--g100);color:var(--g600);">' + esc(m.category || '') + '</span>' +
              '</div>';
          }).join('');

        container.querySelectorAll('.admin-add-discovered').forEach(function(btn) {
          btn.addEventListener('click', function() {
            addDiscoveredModel(btn.dataset.mid, btn.dataset.mname, btn.dataset.mcost, btn.dataset.mcat, btn);
          });
        });
      })
      .catch(function(err) {
        container.innerHTML = '<p style="color:var(--red);font-size:13px;">Request failed: ' + esc(err.message) + '</p>';
      });
  }

  function addDiscoveredModel(id, name, cost, category, btn) {
    fetch('/api/admin/config/models/add-discovered', {
      method: 'POST',
      headers: getAuthHeaders(),
      body: JSON.stringify({ id: id, name: name, cost: cost, category: category })
    })
    .then(function(r) { return r.json(); })
    .then(function(data) {
      if (data.success) {
        showToast('Added: ' + name + ' — now select it as default and click Set Default', 'success');
        if (btn) { btn.textContent = 'Added'; btn.disabled = true; btn.style.background = 'var(--green)'; }
        // Refresh model lists, then auto-select the newly added model
        fetch('/api/admin/config/models', { headers: getAuthHeaders() })
          .then(function(r) { return r.json(); })
          .then(function(refreshed) {
            if (!refreshed.success) return;
            var defaultSel = document.getElementById('admin-default-model');
            if (defaultSel) {
              defaultSel.innerHTML = '';
              refreshed.models.forEach(function(m) {
                var opt = document.createElement('option');
                opt.value = m.id;
                opt.textContent = m.name + (m.enabled === false ? ' (disabled)' : '');
                defaultSel.appendChild(opt);
              });
              (refreshed.custom || []).forEach(function(m) {
                var opt = document.createElement('option');
                opt.value = m.id;
                opt.textContent = m.name;
                defaultSel.appendChild(opt);
              });
              // Auto-select the model just added
              defaultSel.value = id;
            }
            renderCustomModels(refreshed.custom || []);
          });
      } else {
        showToast(data.error || 'Failed', 'error');
      }
    })
    .catch(function() { showToast('Request failed', 'error'); });
  }

  function addCustomModel() {
    var id   = (document.getElementById('admin-custom-model-id')   || {}).value || '';
    var name = (document.getElementById('admin-custom-model-name') || {}).value || '';
    var cost = (document.getElementById('admin-custom-model-cost') || {}).value || '';
    var cat  = (document.getElementById('admin-custom-model-cat')  || {}).value || 'smart';

    if (!id.trim() || !name.trim()) { showToast('Model ID and name required', 'error'); return; }

    fetch('/api/admin/config/models/custom', {
      method: 'POST',
      headers: getAuthHeaders(),
      body: JSON.stringify({ id: id.trim(), name: name.trim(), cost: cost.trim(), category: cat })
    })
    .then(function(r) { return r.json(); })
    .then(function(data) {
      if (data.success) {
        showToast('Custom model added: ' + name, 'success');
        // Clear inputs
        var el = document.getElementById('admin-custom-model-id');   if (el) el.value = '';
        el = document.getElementById('admin-custom-model-name'); if (el) el.value = '';
        el = document.getElementById('admin-custom-model-cost'); if (el) el.value = '';
        loadAdminModels();
      } else {
        showToast(data.error || 'Failed', 'error');
      }
    })
    .catch(function() { showToast('Request failed', 'error'); });
  }

  function renderCustomModels(custom) {
    var container = document.getElementById('admin-custom-models-list');
    if (!container) return;
    if (!custom || custom.length === 0) {
      container.innerHTML = '';
      return;
    }

    container.innerHTML = '<label style="font-size:12px;font-weight:600;color:var(--g600);display:block;margin-bottom:4px;">Custom / Discovered Models</label>' +
      custom.map(function(m) {
        return '<div style="display:flex;align-items:center;gap:8px;padding:5px 8px;border-radius:6px;background:var(--g50);font-size:13px;">' +
          '<span style="flex:1;"><strong>' + esc(m.name) + '</strong> <span style="color:var(--g500);font-size:11px;">(' + esc(m.id) + ')</span></span>' +
          '<span style="font-size:11px;padding:1px 6px;border-radius:4px;background:var(--blue-light, #e0f0ff);color:var(--blue);">' + esc(m.tag || 'CUSTOM') + '</span>' +
          '<span style="font-size:11px;color:var(--g500);">' + esc(m.cost || '') + '</span>' +
          '<button class="btn-sm admin-model-test-btn" data-mid="' + esc(m.id) + '" style="padding:2px 8px;font-size:11px;background:var(--g100);color:var(--g700);border:none;border-radius:4px;cursor:pointer;">Test</button>' +
          '<button class="btn-sm admin-delete-custom" data-mid="' + esc(m.id) + '" style="padding:2px 8px;font-size:11px;background:var(--red-light);color:var(--red);border:none;border-radius:4px;cursor:pointer;">Remove</button>' +
          '</div>';
      }).join('');

    container.querySelectorAll('.admin-delete-custom').forEach(function(btn) {
      btn.addEventListener('click', function() {
        deleteCustomModel(btn.dataset.mid);
      });
    });
  }

  function deleteCustomModel(modelId) {
    fetch('/api/admin/config/models/custom/' + encodeURIComponent(modelId), {
      method: 'DELETE',
      headers: getAuthHeaders()
    })
    .then(function(r) { return r.json(); })
    .then(function(data) {
      if (data.success) {
        showToast('Removed: ' + modelId, 'info');
        loadAdminModels();
      } else {
        showToast(data.error || 'Failed', 'error');
      }
    })
    .catch(function() { showToast('Request failed', 'error'); });
  }

  function clearAllModels() {
    showConfirm('Remove all added models? You will need to re-add them via Search API.', function() {
      Promise.all([
        fetch('/api/admin/config/models/clear-all', { method: 'POST', headers: getAuthHeaders() })
          .then(function(r) { return r.json(); })
      ]).then(function(results) {
        if (results[0].success) {
          showToast('All models cleared', 'info');
          loadAdminModels();
        } else {
          showToast(results[0].error || 'Failed', 'error');
        }
      }).catch(function() { showToast('Request failed', 'error'); });
    });
  }

  function saveDefaultModel() {
    var sel = document.getElementById('admin-default-model');
    if (!sel || !sel.value) { showToast('Select a model', 'error'); return; }

    fetch('/api/admin/config/models/default', {
      method: 'PUT',
      headers: getAuthHeaders(),
      body: JSON.stringify({ modelId: sel.value })
    })
    .then(function(r) { return r.json(); })
    .then(function(data) {
      if (data.success) showToast('Default model set: ' + sel.value, 'success');
      else showToast(data.error || 'Failed', 'error');
    })
    .catch(function() { showToast('Request failed', 'error'); });
  }

  function testModel(modelId, btn) {
    if (!modelId) return;
    var origText = btn ? btn.textContent : 'Test';
    adminSetButtonText(btn, '...', true);

    fetch('/api/admin/config/models/test', {
      method: 'POST',
      headers: getAuthHeaders(),
      body: JSON.stringify({ modelId: modelId })
    })
    .then(function(r) { return r.json(); })
    .then(function(data) {
      adminSetButtonText(btn, origText, false);
      if (data.success) {
        showToast('"' + (data.response || '?') + '" — ' + modelId + ' (' + (data.duration || 0) + 'ms)', 'success');
      } else {
        showToast('Test failed: ' + (data.error || 'Unknown error'), 'error');
      }
    })
    .catch(function() {
      adminSetButtonText(btn, origText, false);
      showToast('Request failed', 'error');
    });
  }

}

// ============================================================
// ADMIN TTS MANAGEMENT
// ============================================================
{
  document.addEventListener('tabChanged', function(e) {
    if (e.detail && e.detail.tab === 'admin') loadTTSConfig();
  });
  document.addEventListener('click', function(e) {
    if (e.target.closest('#btn-test-tts'))    testTTS();
    if (e.target.closest('#btn-discover-tts')) discoverTTS();
    if (e.target.closest('.admin-tts-set-btn')) {
      var btn = e.target.closest('.admin-tts-set-btn');
      setTTSDefault(btn.dataset.id, btn.dataset.type, btn);
    }
  });
  document.addEventListener('keydown', function(e) {
    if (e.target.id === 'admin-tts-search' && e.key === 'Enter') { e.preventDefault(); discoverTTS(); }
  });

  const esc = adminEscapeHtml;

  function loadTTSConfig() {
    fetch('/api/admin/config/tts', { headers: getAuthHeaders() })
      .then(function(r) { return r.json(); })
      .then(function(data) {
        if (!data.success) return;
        var badge = document.getElementById('admin-tts-provider-badge');
        if (badge) {
          badge.textContent = (data.provider || 'none').toUpperCase();
          badge.style.background = data.provider === 'none' ? 'var(--red-light)' : 'var(--g100)';
          badge.style.color = data.provider === 'none' ? 'var(--red)' : 'var(--g600)';
        }
        var info = document.getElementById('admin-tts-info');
        if (info) {
          var parts = [];
          if (data.envProvider !== 'auto') parts.push('TTS_PROVIDER=' + data.envProvider);
          if (data.dbVoice) parts.push('DB voice: ' + data.dbVoice);
          else if (data.envVoice) parts.push('Env voice: ' + data.envVoice);
          if (data.dbModel) parts.push('DB model: ' + data.dbModel);
          else if (data.envModel) parts.push('Env model: ' + data.envModel);
          var configured = Object.keys(data.configured || {}).filter(function(k) { return data.configured[k]; });
          if (configured.length) parts.push('Configured: ' + configured.join(', '));
          info.textContent = parts.join(' · ') || 'Auto-detected from env';
        }
        var voiceSel = document.getElementById('admin-tts-voice');
        if (voiceSel) {
          voiceSel.innerHTML = '';
          var voices = (data.voices && data.voices[data.provider]) || [];
          if (data.currentVoice && voices.indexOf(data.currentVoice) === -1) voices = [data.currentVoice].concat(voices);
          if (voices.length === 0) voices = ['default'];
          voices.forEach(function(v) {
            var opt = document.createElement('option');
            opt.value = v;
            opt.textContent = v + (v === data.currentVoice ? ' (active)' : '');
            if (v === data.currentVoice) opt.selected = true;
            voiceSel.appendChild(opt);
          });
        }
      })
      .catch(function() {});
  }

  function discoverTTS() {
    var search = (document.getElementById('admin-tts-search') || {}).value || '';
    var container = document.getElementById('admin-tts-discovered');
    var hint = document.getElementById('admin-tts-discover-hint');
    if (!container) return;
    container.innerHTML = '<p style="font-size:13px;color:var(--g400);"><i class="fas fa-spinner fa-spin"></i> Querying provider...</p>';
    if (hint) hint.style.display = 'none';

    fetch('/api/admin/config/tts/discover?q=' + encodeURIComponent(search), { headers: getAuthHeaders() })
      .then(function(r) { return r.json(); })
      .then(function(data) {
        if (!data.success) {
          container.innerHTML = '<p style="font-size:13px;color:var(--red);">Error: ' + esc(data.error || 'Unknown') + '</p>';
          return;
        }
        var items = data.voices || [];
        if (items.length === 0) {
          container.innerHTML = '<p style="font-size:13px;color:var(--g400);">No voices/models found' + (search ? ' matching "' + esc(search) + '"' : '') + '</p>';
          return;
        }
        container.innerHTML = '<p style="font-size:12px;color:var(--g500);margin:0 0 6px;">Found ' + data.count + ' voices/models (provider: ' + esc(data.provider) + ')</p>' +
          items.slice(0, 100).map(function(v) {
            var isModel = v.kind === 'model' || (v.source || '').indexOf('gateway') !== -1 || (v.source || '').indexOf('builtin-model') !== -1 || (v.source || '').indexOf('configured-model') !== -1;
            var setType = isModel ? 'model' : 'voice';
            var badge = isModel ? '<span style="font-size:9px;padding:1px 5px;border-radius:4px;background:var(--blue);color:white;margin-left:4px;">MODEL</span>' : '<span style="font-size:9px;padding:1px 5px;border-radius:4px;background:var(--green);color:white;margin-left:4px;">VOICE</span>';
            return '<div style="display:flex;align-items:center;gap:8px;padding:5px 8px;border-radius:6px;background:var(--g50);font-size:13px;">' +
              '<button class="btn-sm btn-primary admin-tts-set-btn" data-id="' + esc(v.id) + '" data-type="' + setType + '" style="padding:2px 8px;font-size:11px;">Set</button>' +
              '<span style="flex:1;">' + esc(v.name) + badge + '</span>' +
              '<span style="font-size:10px;color:var(--g400);">' + esc(v.source || '') + '</span>' +
              '</div>';
          }).join('');
      })
      .catch(function(err) {
        container.innerHTML = '<p style="font-size:13px;color:var(--red);">Request failed: ' + esc(err.message) + '</p>';
      });
  }

  function setTTSDefault(id, type, btn) {
    var key = type === 'model' ? 'tts.model' : 'tts.voice';
    var origText = btn ? btn.textContent : '';
    adminSetButtonText(btn, '...', true);

    fetch('/api/admin/config/' + encodeURIComponent(key), {
      method: 'PUT',
      headers: getAuthHeaders(),
      body: JSON.stringify({ value: id })
    })
    .then(function(r) { return r.json(); })
    .then(function(data) {
      adminSetButtonText(btn, 'Set', false);
      adminFlashButtonBackground(btn, 'var(--green)');
      if (data.success) {
        showToast('TTS ' + type + ' set to: ' + id, 'success');
        // Update voice selector
        var voiceSel = document.getElementById('admin-tts-voice');
        if (voiceSel && type === 'voice') {
          var found = Array.from(voiceSel.options).find(function(o) { return o.value === id; });
          if (!found) {
            var opt = document.createElement('option');
            opt.value = id; opt.textContent = id + ' (active)';
            voiceSel.insertBefore(opt, voiceSel.firstChild);
          }
          voiceSel.value = id;
        }
        loadTTSConfig();
      } else {
        showToast(data.error || 'Failed', 'error');
      }
    })
    .catch(function() {
      adminSetButtonText(btn, origText, false);
      showToast('Request failed', 'error');
    });
  }

  function testTTS() {
    var text = (document.getElementById('admin-tts-test-text') || {}).value || 'Hello.';
    var voice = (document.getElementById('admin-tts-voice') || {}).value || '';
    var btn = document.getElementById('btn-test-tts');
    var resultEl = document.getElementById('admin-tts-result');
    var audioEl = document.getElementById('admin-tts-audio');
    adminSetButtonHtml(btn, '<i class="fas fa-spinner fa-spin"></i> Synthesizing...', true);
    if (resultEl) resultEl.textContent = '';
    if (audioEl) audioEl.style.display = 'none';

    fetch('/api/admin/config/tts/test', {
      method: 'POST',
      headers: getAuthHeaders(),
      body: JSON.stringify({ text: text, voice: voice })
    })
    .then(function(r) { return r.json(); })
    .then(function(data) {
      adminSetButtonHtml(btn, '<i class="fas fa-play"></i> Synthesize &amp; Play', false);
      if (!data.success) {
        if (resultEl) resultEl.textContent = 'Error: ' + (data.error || 'Unknown error');
        return;
      }
      if (audioEl && data.audio) {
        var blob = base64ToBlob(data.audio, 'audio/mpeg');
        audioEl.src = URL.createObjectURL(blob);
        audioEl.style.display = 'inline-block';
        audioEl.play();
      }
      if (resultEl) resultEl.textContent = 'Provider: ' + (data.provider || '?') + ' · Voice: ' + (data.voice || '?');
    })
    .catch(function(err) {
      adminSetButtonHtml(btn, '<i class="fas fa-play"></i> Synthesize &amp; Play', false);
      if (resultEl) resultEl.textContent = 'Request failed: ' + err.message;
    });
  }

  function base64ToBlob(base64, type) {
    var binary = atob(base64);
    var bytes = new Uint8Array(binary.length);
    for (var i = 0; i < binary.length; i++) bytes[i] = binary.charCodeAt(i);
    return new Blob([bytes], { type: type });
  }

}

// ============================================================
// ADMIN STT MANAGEMENT
// ============================================================
{
  let mediaRecorder = null;
  let audioChunks = [];
  let recording = false;

  document.addEventListener('tabChanged', function(e) {
    if (e.detail && e.detail.tab === 'admin') loadSTTConfig();
  });
  document.addEventListener('click', function(e) {
    if (e.target.closest('#btn-stt-record'))    toggleRecording();
    if (e.target.closest('#btn-discover-stt'))  discoverSTT();
    if (e.target.closest('.admin-stt-set-btn')) {
      var btn = e.target.closest('.admin-stt-set-btn');
      setSTTDefault(btn.dataset.id, btn);
    }
  });
  document.addEventListener('keydown', function(e) {
    if (e.target.id === 'admin-stt-search' && e.key === 'Enter') { e.preventDefault(); discoverSTT(); }
  });

  const esc = adminEscapeHtml;

  function loadSTTConfig() {
    fetch('/api/admin/config/stt', { headers: getAuthHeaders() })
      .then(function(r) { return r.json(); })
      .then(function(data) {
        if (!data.success) return;
        var badge = document.getElementById('admin-stt-provider-badge');
        if (badge) {
          badge.textContent = (data.provider || 'none').toUpperCase();
          badge.style.background = data.provider === 'none' ? 'var(--red-light)' : 'var(--g100)';
          badge.style.color = data.provider === 'none' ? 'var(--red)' : 'var(--g600)';
        }
        var info = document.getElementById('admin-stt-info');
        if (info) {
          var parts = [];
          if (data.envProvider !== 'auto') parts.push('TRANSCRIBE_PROVIDER=' + data.envProvider);
          if (data.dbModel) parts.push('DB model: ' + data.dbModel);
          else if (data.envModel) parts.push('Env model: ' + data.envModel);
          var configured = Object.keys(data.configured || {}).filter(function(k) { return data.configured[k]; });
          if (configured.length) parts.push('Configured: ' + configured.join(', '));
          info.textContent = parts.join(' · ') || 'Auto-detected from env';
        }
      })
      .catch(function() {});
  }

  function discoverSTT() {
    var search = (document.getElementById('admin-stt-search') || {}).value || '';
    var container = document.getElementById('admin-stt-discovered');
    var hint = document.getElementById('admin-stt-discover-hint');
    if (!container) return;
    container.innerHTML = '<p style="font-size:13px;color:var(--g400);"><i class="fas fa-spinner fa-spin"></i> Querying provider...</p>';
    if (hint) hint.style.display = 'none';

    fetch('/api/admin/config/stt/discover?q=' + encodeURIComponent(search), { headers: getAuthHeaders() })
      .then(function(r) { return r.json(); })
      .then(function(data) {
        if (!data.success) {
          container.innerHTML = '<p style="font-size:13px;color:var(--red);">Error: ' + esc(data.error || 'Unknown') + '</p>';
          return;
        }
        var items = data.models || [];
        if (items.length === 0) {
          container.innerHTML = '<p style="font-size:13px;color:var(--g400);">No models found' + (search ? ' matching "' + esc(search) + '"' : '') + '</p>';
          return;
        }
        container.innerHTML = '<p style="font-size:12px;color:var(--g500);margin:0 0 6px;">Found ' + data.count + ' models (provider: ' + esc(data.provider) + ')</p>' +
          items.map(function(m) {
            return '<div style="display:flex;align-items:center;gap:8px;padding:5px 8px;border-radius:6px;background:var(--g50);font-size:13px;">' +
              '<button class="btn-sm btn-primary admin-stt-set-btn" data-id="' + esc(m.id) + '" style="padding:2px 8px;font-size:11px;">Set</button>' +
              '<span style="flex:1;">' + esc(m.name || m.id) + '</span>' +
              '<span style="font-size:10px;color:var(--g400);">' + esc(m.source || '') + '</span>' +
              '</div>';
          }).join('');
      })
      .catch(function(err) {
        container.innerHTML = '<p style="font-size:13px;color:var(--red);">Request failed: ' + esc(err.message) + '</p>';
      });
  }

  function setSTTDefault(modelId, btn) {
    var origText = btn ? btn.textContent : '';
    adminSetButtonText(btn, '...', true);
    fetch('/api/admin/config/' + encodeURIComponent('stt.model'), {
      method: 'PUT',
      headers: getAuthHeaders(),
      body: JSON.stringify({ value: modelId })
    })
    .then(function(r) { return r.json(); })
    .then(function(data) {
      adminSetButtonText(btn, 'Set', false);
      adminFlashButtonBackground(btn, data.success ? 'var(--green)' : '');
      if (data.success) { showToast('STT model set to: ' + modelId, 'success'); loadSTTConfig(); }
      else showToast(data.error || 'Failed', 'error');
    })
    .catch(function() {
      adminSetButtonText(btn, origText, false);
      showToast('Request failed', 'error');
    });
  }

  function toggleRecording() {
    if (recording) {
      stopRecording();
    } else {
      startRecording();
    }
  }

  function startRecording() {
    var btn = document.getElementById('btn-stt-record');
    var status = document.getElementById('admin-stt-recording-status');
    var resultEl = document.getElementById('admin-stt-result');
    if (resultEl) resultEl.style.display = 'none';

    navigator.mediaDevices.getUserMedia({ audio: true })
      .then(function(stream) {
        audioChunks = [];
        mediaRecorder = new MediaRecorder(stream);
        mediaRecorder.addEventListener('dataavailable', function(e) {
          if (e.data.size > 0) audioChunks.push(e.data);
        });
        mediaRecorder.addEventListener('stop', function() {
          stream.getTracks().forEach(function(t) { t.stop(); });
          transcribeRecording();
        });
        mediaRecorder.start();
        recording = true;
        if (btn) { btn.innerHTML = '<i class="fas fa-stop"></i> Stop Recording'; btn.style.background = 'var(--red)'; btn.style.color = 'white'; }
        if (status) status.textContent = 'Recording... (click Stop when done)';
      })
      .catch(function(err) {
        if (status) status.textContent = 'Microphone access denied: ' + err.message;
      });
  }

  function stopRecording() {
    if (mediaRecorder && mediaRecorder.state !== 'inactive') {
      mediaRecorder.stop();
    }
    recording = false;
    var btn = document.getElementById('btn-stt-record');
    var status = document.getElementById('admin-stt-recording-status');
    if (btn) { btn.innerHTML = '<i class="fas fa-microphone"></i> Start Recording'; btn.style.background = ''; btn.style.color = ''; }
    if (status) status.textContent = 'Processing...';
  }

  function transcribeRecording() {
    if (audioChunks.length === 0) return;
    var blob = new Blob(audioChunks, { type: 'audio/webm' });
    var reader = new FileReader();
    reader.onloadend = function() {
      var base64 = reader.result.split(',')[1];
      fetch('/api/admin/config/stt/test', {
        method: 'POST',
        headers: getAuthHeaders(),
        body: JSON.stringify({ audioBase64: base64, mimeType: 'audio/webm' })
      })
      .then(function(r) { return r.json(); })
      .then(function(data) {
        var status = document.getElementById('admin-stt-recording-status');
        var resultEl = document.getElementById('admin-stt-result');
        var textEl = document.getElementById('admin-stt-text');
        var metaEl = document.getElementById('admin-stt-meta');
        if (status) status.textContent = '';
        if (resultEl) resultEl.style.display = 'block';
        if (data.success) {
          if (textEl) textEl.textContent = data.text || '(empty result)';
          if (metaEl) metaEl.textContent = 'Provider: ' + (data.provider || '?') + ' · ' + (data.duration || 0) + 'ms';
        } else {
          if (textEl) textEl.textContent = 'Error: ' + (data.error || 'Unknown error');
          if (metaEl) metaEl.textContent = '';
        }
      })
      .catch(function(err) {
        var status = document.getElementById('admin-stt-recording-status');
        if (status) status.textContent = 'Request failed: ' + err.message;
      });
    };
    reader.readAsDataURL(blob);
  }

}

// ============================================================
// ADMIN EMBEDDING MODELS MANAGEMENT
// ============================================================
{
  document.addEventListener('tabChanged', function(e) {
    if (e.detail && e.detail.tab === 'admin') loadEmbeddingConfig();
  });
  document.addEventListener('click', function(e) {
    if (e.target.closest('#btn-test-embedding'))     testEmbedding();
    if (e.target.closest('#btn-discover-embeddings')) discoverEmbeddings();
    if (e.target.closest('.admin-embed-set-btn')) {
      var btn = e.target.closest('.admin-embed-set-btn');
      setEmbeddingDefault(btn.dataset.id, btn.dataset.dims, btn);
    }
  });
  document.addEventListener('keydown', function(e) {
    if (e.target.id === 'admin-embed-search' && e.key === 'Enter') { e.preventDefault(); discoverEmbeddings(); }
  });

  const esc = adminEscapeHtml;

  function loadEmbeddingConfig() {
    fetch('/api/admin/config/embeddings', { headers: getAuthHeaders() })
      .then(function(r) { return r.json(); })
      .then(function(data) {
        if (!data.success) return;
        var badge = document.getElementById('admin-embed-provider-badge');
        if (badge) {
          badge.textContent = (data.provider || 'none').toUpperCase();
          badge.style.background = data.configured ? 'var(--g100)' : 'var(--red-light)';
          badge.style.color = data.configured ? 'var(--g600)' : 'var(--red)';
        }
        var info = document.getElementById('admin-embed-info');
        if (info) {
          var parts = [];
          if (data.dbModel) parts.push('DB model: ' + data.dbModel);
          else if (data.envModel) parts.push('Env model: ' + data.envModel);
          parts.push('Dims: ' + (data.currentDimensions || '?'));
          if (!data.configured) parts.push('⚠️ Not configured');
          info.textContent = parts.join(' · ');
        }
        var modelsEl = document.getElementById('admin-embed-models');
        if (modelsEl && data.models) {
          modelsEl.innerHTML = data.models.map(function(m) {
            var isCurrent = m.id === data.currentModel;
            return '<div style="display:flex;align-items:center;gap:8px;padding:5px 8px;border-radius:6px;background:var(--g50);font-size:13px;">' +
              '<button class="btn-sm admin-embed-set-btn" data-id="' + esc(m.id) + '" data-dims="' + m.dims + '" style="padding:2px 8px;font-size:11px;background:var(--g100);color:var(--g700);border:none;border-radius:4px;cursor:pointer;">Set</button>' +
              '<span style="flex:1;"><strong>' + esc(m.name) + '</strong> <span style="color:var(--g500);font-size:11px;">(' + m.dims + 'd)</span></span>' +
              '<span style="font-size:11px;padding:1px 6px;border-radius:4px;background:var(--g100);color:var(--g600);">' + esc(m.tag || '') + '</span>' +
              (isCurrent ? '<span style="font-size:11px;padding:1px 6px;border-radius:4px;background:var(--green-light,#d1fae5);color:var(--green);">ACTIVE</span>' : '') +
              '</div>';
          }).join('');
        }
      })
      .catch(function() {});
  }

  function discoverEmbeddings() {
    var search = (document.getElementById('admin-embed-search') || {}).value || '';
    var container = document.getElementById('admin-embed-discovered');
    var hint = document.getElementById('admin-embed-discover-hint');
    if (!container) return;
    container.innerHTML = '<p style="font-size:13px;color:var(--g400);"><i class="fas fa-spinner fa-spin"></i> Querying provider...</p>';
    if (hint) hint.style.display = 'none';

    fetch('/api/admin/config/embeddings/discover?q=' + encodeURIComponent(search), { headers: getAuthHeaders() })
      .then(function(r) { return r.json(); })
      .then(function(data) {
        if (!data.success) {
          container.innerHTML = '<p style="font-size:13px;color:var(--red);">Error: ' + esc(data.error || 'Unknown') + '</p>';
          return;
        }
        var items = data.models || [];
        if (items.length === 0) {
          container.innerHTML = '<p style="font-size:13px;color:var(--g400);">No models found' + (search ? ' matching "' + esc(search) + '"' : '') + '</p>';
          return;
        }
        container.innerHTML = '<p style="font-size:12px;color:var(--g500);margin:0 0 6px;">Found ' + data.count + ' models (provider: ' + esc(data.provider) + ')</p>' +
          items.map(function(m) {
            return '<div style="display:flex;align-items:center;gap:8px;padding:5px 8px;border-radius:6px;background:var(--g50);font-size:13px;">' +
              '<button class="btn-sm btn-primary admin-embed-set-btn" data-id="' + esc(m.id) + '" data-dims="' + (m.dims || '') + '" style="padding:2px 8px;font-size:11px;">Set</button>' +
              '<span style="flex:1;">' + esc(m.name || m.id) + (m.dims && m.dims !== '?' ? ' <span style="color:var(--g500);font-size:11px;">(' + m.dims + 'd)</span>' : '') + '</span>' +
              '<span style="font-size:10px;color:var(--g400);">' + esc(m.source || '') + '</span>' +
              '</div>';
          }).join('');
      })
      .catch(function(err) {
        container.innerHTML = '<p style="font-size:13px;color:var(--red);">Request failed: ' + esc(err.message) + '</p>';
      });
  }

  function setEmbeddingDefault(modelId, dims, btn) {
    var origText = btn ? btn.textContent : '';
    adminSetButtonText(btn, '...', true);
    var promises = [
      fetch('/api/admin/config/' + encodeURIComponent('embeddings.model'), {
        method: 'PUT', headers: getAuthHeaders(), body: JSON.stringify({ value: modelId })
      }).then(function(r) { return r.json(); })
    ];
    if (dims && dims !== '?') {
      promises.push(
        fetch('/api/admin/config/' + encodeURIComponent('embeddings.dimensions'), {
          method: 'PUT', headers: getAuthHeaders(), body: JSON.stringify({ value: String(dims) })
        }).then(function(r) { return r.json(); })
      );
    }
    Promise.all(promises)
      .then(function(results) {
        var ok = results.every(function(r) { return r.success; });
        adminSetButtonText(btn, 'Set', false);
        adminFlashButtonBackground(btn, ok ? 'var(--green)' : '');
        if (ok) { showToast('Embedding model set to: ' + modelId + (dims ? ' (' + dims + 'd)' : ''), 'success'); loadEmbeddingConfig(); }
        else showToast(results[0].error || 'Failed', 'error');
      })
      .catch(function() {
        adminSetButtonText(btn, origText, false);
        showToast('Request failed', 'error');
      });
  }

  function testEmbedding() {
    var text = (document.getElementById('admin-embed-test-text') || {}).value || 'test';
    var resultEl = document.getElementById('admin-embed-result');
    var btn = document.getElementById('btn-test-embedding');
    adminSetButtonHtml(btn, '<i class="fas fa-spinner fa-spin"></i>', true);
    if (resultEl) resultEl.textContent = 'Generating...';

    fetch('/api/admin/config/embeddings/test', {
      method: 'POST',
      headers: getAuthHeaders(),
      body: JSON.stringify({ text: text })
    })
    .then(function(r) { return r.json(); })
    .then(function(data) {
      adminSetButtonHtml(btn, '<i class="fas fa-code-branch"></i> Generate', false);
      if (!data.success) {
        if (resultEl) resultEl.innerHTML = '<span style="color:var(--red);">Error: ' + esc(data.error || 'Failed') + '</span>';
        return;
      }
      if (resultEl) {
        resultEl.innerHTML =
          '<strong>Dimensions:</strong> ' + data.dimensions + ' &nbsp;|&nbsp; ' +
          '<strong>Model:</strong> ' + esc(data.model) + ' &nbsp;|&nbsp; ' +
          '<strong>' + data.duration + 'ms</strong>' +
          '<div style="margin-top:4px;font-family:monospace;font-size:11px;color:var(--g400);">Sample: [' + (data.sample || []).join(', ') + ', ...]</div>';
      }
    })
    .catch(function(err) {
      adminSetButtonHtml(btn, '<i class="fas fa-code-branch"></i> Generate', false);
      if (resultEl) resultEl.textContent = 'Request failed: ' + err.message;
    });
  }

}
