(() => {
  const DEFAULT_PROVIDERS = ['openrouter', 'mistral', 'google', 'groq', 'nvidia', 'chutes', 'cerebras', 'ollama', 'opencode', 'cohere'];
  const PLANNING_PROVIDERS = ['openrouter', 'mistral', 'google', 'groq', 'nvidia', 'chutes', 'cerebras', 'ollama', 'cohere'];
  const pageType = document?.body?.dataset?.page || 'build';
  console.log('Admin JS loaded, pageType:', pageType);
  const state = {
    available: [],
    configured: [],
    opencodeModels: [], // Models from OpenCode (order determines fallback chain for execution)
    publicModels: [], // Public-facing models (displayed to users in builder dropdown)
    icons: [],
    accounts: [],
    affiliates: [],
    withdrawals: [],
    planSettings: { provider: 'openrouter', freePlanModel: '', planningChain: [] },
    providerLimits: {},
    providerUsage: [],
    opencodeBackupModel: '',
    providerOptions: [],
    providerModels: {},
    tokenRates: {},
  };

  const el = {
    // OpenCode Models (fallback chain)
    opencodeModelForm: document.getElementById('opencode-model-form'),
    opencodeModelSelect: document.getElementById('opencode-model-select'),
    opencodeModelLabel: document.getElementById('opencode-model-label'),
    opencodeModelTier: document.getElementById('opencode-model-tier'),
    opencodeModelIcon: document.getElementById('opencode-model-icon'),
    opencodeModelMedia: document.getElementById('opencode-model-media'),
    opencodeModelStatus: document.getElementById('opencode-model-status'),
    reloadOpencodeModels: document.getElementById('reload-opencode-models'),
    opencodeModelsList: document.getElementById('opencode-models-list'),
    opencodeModelsCount: document.getElementById('opencode-models-count'),
    // Public Models (user-facing selection)
    publicModelForm: document.getElementById('public-model-form'),
    publicModelName: document.getElementById('public-model-name'),
    publicModelLabel: document.getElementById('public-model-label'),
    publicModelTier: document.getElementById('public-model-tier'),
    publicModelIcon: document.getElementById('public-model-icon'),
    publicModelMedia: document.getElementById('public-model-media'),
    publicModelStatus: document.getElementById('public-model-status'),
    publicModelsList: document.getElementById('public-models-list'),
    publicModelsCount: document.getElementById('public-models-count'),
    // Provider chain (legacy - kept for compatibility)
    providerChainForm: document.getElementById('provider-chain-form'),
    chainProvider: document.getElementById('chain-provider'),
    chainModel: document.getElementById('chain-model'),
    providerChainList: document.getElementById('provider-chain-list'),
    providerChainCount: document.getElementById('provider-chain-count'),
    // Legacy elements (keep for compatibility)
    availableModels: document.getElementById('available-models'),
    displayLabel: document.getElementById('display-label'),
    modelTier: document.getElementById('model-tier'),
    iconSelect: document.getElementById('icon-select'),
    iconList: document.getElementById('icon-list'),
    modelForm: document.getElementById('model-form'),
    status: document.getElementById('admin-status'),
    configuredList: document.getElementById('configured-list'),
    configuredCount: document.getElementById('configured-count'),
    logout: document.getElementById('admin-logout'),
    refresh: document.getElementById('admin-refresh'),
    reloadAvailable: document.getElementById('reload-available'),
    // legacy planning fields (build page no longer renders these)
    orForm: document.getElementById('openrouter-form'),
    orPrimary: document.getElementById('or-primary'),
    orBackup1: document.getElementById('or-backup1'),
    orBackup2: document.getElementById('or-backup2'),
    orBackup3: document.getElementById('or-backup3'),
    orStatus: document.getElementById('or-status'),
    autoModelForm: document.getElementById('auto-model-form'),
    autoModelSelect: document.getElementById('auto-model-select'),
    autoModelStatus: document.getElementById('auto-model-status'),
    planProviderForm: document.getElementById('plan-provider-form'),
    planProvider: document.getElementById('plan-provider'),
    freePlanModel: document.getElementById('free-plan-model'),
    planProviderStatus: document.getElementById('plan-provider-status'),
    planPriorityList: document.getElementById('plan-priority-list'),
    addPlanRow: document.getElementById('add-plan-row'),
    planChainStatus: document.getElementById('plan-chain-status'),
    mistralForm: document.getElementById('mistral-form'),
    mistralPrimary: document.getElementById('mistral-primary'),
    mistralBackup1: document.getElementById('mistral-backup1'),
    mistralBackup2: document.getElementById('mistral-backup2'),
    mistralBackup3: document.getElementById('mistral-backup3'),
    mistralStatus: document.getElementById('mistral-status'),
    accountsTable: document.getElementById('accounts-table'),
    accountsCount: document.getElementById('accounts-count'),
    affiliatesTable: document.getElementById('affiliates-table'),
    affiliatesCount: document.getElementById('affiliates-count'),
    withdrawalsTable: document.getElementById('withdrawals-table'),
    withdrawalsCount: document.getElementById('withdrawals-count'),
    providerOrder: document.getElementById('provider-order'),
    providerLimitForm: document.getElementById('provider-limit-form'),
    limitProvider: document.getElementById('limit-provider'),
    limitScope: document.getElementById('limit-scope'),
    limitModel: document.getElementById('limit-model'),
    limitModelInput: document.getElementById('limit-model-input'),
    limitTpm: document.getElementById('limit-tpm'),
    limitTph: document.getElementById('limit-tph'),
    limitTpd: document.getElementById('limit-tpd'),
    limitRpm: document.getElementById('limit-rpm'),
    limitRph: document.getElementById('limit-rph'),
    limitRpd: document.getElementById('limit-rpd'),
    limitBackup: document.getElementById('limit-backup'),
    providerLimitStatus: document.getElementById('provider-limit-status'),
    providerUsage: document.getElementById('provider-usage'),
    availableModelDatalist: document.getElementById('available-model-datalist'),
    supportsMedia: document.getElementById('supports-media'),
    // Plan tokens UI
    planTokensTable: document.getElementById('plan-tokens-table'),
    savePlanTokens: document.getElementById('save-plan-tokens'),
    planTokensStatus: document.getElementById('plan-tokens-status'),
    tokenRateUsd: document.getElementById('token-rate-usd'),
    tokenRateGbp: document.getElementById('token-rate-gbp'),
    tokenRateEur: document.getElementById('token-rate-eur'),
    saveTokenRates: document.getElementById('save-token-rates'),
    tokenRatesStatus: document.getElementById('token-rates-status'),
    // Cancel messages UI
    cancelAllMessages: document.getElementById('cancel-all-messages'),
    cancelMessagesStatus: document.getElementById('cancel-messages-status'),
    opencodeBackupForm: document.getElementById('opencode-backup-form'),
    opencodeBackup: document.getElementById('opencode-backup'),
    opencodeBackupStatus: document.getElementById('opencode-backup-status'),
    externalTestingRun: document.getElementById('external-testing-run'),
    externalTestingStatus: document.getElementById('external-testing-status'),
    externalTestingOutput: document.getElementById('external-testing-output'),
    externalTestingConfig: document.getElementById('external-testing-config'),
    ollamaTestRun: document.getElementById('ollama-test-run'),
    ollamaTestStatus: document.getElementById('ollama-test-status'),
    ollamaTestOutput: document.getElementById('ollama-test-output'),
  };
  console.log('Element check - opencodeBackupForm:', el.opencodeBackupForm);
  console.log('Element check - opencodeBackup:', el.opencodeBackup);
  console.log('Element check - opencodeBackupStatus:', el.opencodeBackupStatus);

  function ensureAvailableDatalist() {
    if (el.availableModelDatalist) return el.availableModelDatalist;
    const dl = document.createElement('datalist');
    dl.id = 'available-model-datalist';
    document.body.appendChild(dl);
    el.availableModelDatalist = dl;
    return dl;
  }

  function getAvailableModelNames() {
    const names = new Set();
    (state.available || []).forEach((m) => {
      const name = m.name || m.id || m;
      if (name) names.add(name);
    });
    (state.configured || []).forEach((m) => { if (m.name) names.add(m.name); });
    // include provider-specific models discovered by provider limits endpoint
    Object.values(state.providerModels || {}).forEach((arr) => {
      (arr || []).forEach((name) => { if (name) names.add(name); });
    });
    return Array.from(names);
  }

  function syncAvailableModelDatalist() {
    const dl = ensureAvailableDatalist();
    if (!dl) return;
    dl.innerHTML = '';
    getAvailableModelNames().forEach((name) => {
      const opt = document.createElement('option');
      opt.value = name;
      dl.appendChild(opt);
    });
  }

  function setStatus(msg, isError = false) {
    if (!el.status) return;
    el.status.textContent = msg || '';
    el.status.style.color = isError ? 'var(--danger)' : 'inherit';
  }

  function setOrStatus(msg, isError = false) {
    if (!el.orStatus) return;
    el.orStatus.textContent = msg || '';
    el.orStatus.style.color = isError ? 'var(--danger)' : 'inherit';
  }

  function setMistralStatus(msg, isError = false) {
    if (!el.mistralStatus) return;
    el.mistralStatus.textContent = msg || '';
    el.mistralStatus.style.color = isError ? 'var(--danger)' : 'inherit';
  }

  function setPlanProviderStatus(msg, isError = false) {
    if (!el.planProviderStatus) return;
    el.planProviderStatus.textContent = msg || '';
    el.planProviderStatus.style.color = isError ? 'var(--danger)' : 'inherit';
  }

  function setPlanChainStatus(msg, isError = false) {
    if (!el.planChainStatus) return;
    el.planChainStatus.textContent = msg || '';
    el.planChainStatus.style.color = isError ? 'var(--danger)' : 'inherit';
  }

  function setProviderLimitStatus(msg, isError = false) {
    if (!el.providerLimitStatus) return;
    el.providerLimitStatus.textContent = msg || '';
    el.providerLimitStatus.style.color = isError ? 'var(--danger)' : 'inherit';
  }

  function setAutoModelStatus(msg, isError = false) {
    if (!el.autoModelStatus) return;
    el.autoModelStatus.textContent = msg || '';
    el.autoModelStatus.style.color = isError ? 'var(--danger)' : 'inherit';
  }

  function setPublicModelStatus(msg, isError = false) {
    if (!el.publicModelStatus) return;
    el.publicModelStatus.textContent = msg || '';
    el.publicModelStatus.style.color = isError ? 'var(--danger)' : 'inherit';
  }

  function setOpencodeModelStatus(msg, isError = false) {
    if (!el.opencodeModelStatus) return;
    el.opencodeModelStatus.textContent = msg || '';
    el.opencodeModelStatus.style.color = isError ? 'var(--danger)' : 'inherit';
  }

  function setProviderChainStatus(msg, isError = false) {
    if (!el.providerChainStatus) return;
    el.providerChainStatus.textContent = msg || '';
    el.providerChainStatus.style.color = isError ? 'var(--danger)' : 'inherit';
  }

  function setOpencodeBackupStatus(msg, isError = false) {
    if (!el.opencodeBackupStatus) return;
    el.opencodeBackupStatus.textContent = msg || '';
    el.opencodeBackupStatus.style.color = isError ? 'var(--danger)' : 'inherit';
  }

  function setExternalTestingStatus(msg, isError = false) {
    if (!el.externalTestingStatus) return;
    el.externalTestingStatus.textContent = msg || '';
    el.externalTestingStatus.style.color = isError ? 'var(--danger)' : 'inherit';
  }

  function renderExternalTestingConfig(config) {
    if (!el.externalTestingConfig) return;
    el.externalTestingConfig.innerHTML = '';
    if (!config) return;
    const rows = [
      ['WP host', config.wpHost || '—'],
      ['WP path', config.wpPath || '—'],
      ['Base URL', config.wpBaseUrl || '—'],
      ['Multisite enabled', config.enableMultisite ? 'Yes' : 'No'],
      ['Subsite mode', config.subsiteMode || '—'],
      ['Subsite domain', config.subsiteDomain || '—'],
      ['Max concurrent tests', String(config.maxConcurrentTests ?? '—')],
      ['Auto cleanup', config.autoCleanup ? 'Yes' : 'No'],
      ['Cleanup delay (ms)', String(config.cleanupDelayMs ?? '—')],
      ['SSH key configured', config.sshKeyConfigured ? 'Yes' : 'No'],
    ];

    rows.forEach(([label, value]) => {
      const row = document.createElement('div');
      row.className = 'admin-row';
      const labelWrap = document.createElement('div');
      labelWrap.style.minWidth = '180px';
      const strong = document.createElement('strong');
      strong.textContent = label;
      labelWrap.appendChild(strong);
      const valueWrap = document.createElement('div');
      valueWrap.textContent = value;
      row.appendChild(labelWrap);
      row.appendChild(valueWrap);
      el.externalTestingConfig.appendChild(row);
    });
  }

  function renderExternalTestingOutput(result) {
    if (!el.externalTestingOutput) return;
    el.externalTestingOutput.innerHTML = '';
    if (!result) return;

    const summary = document.createElement('div');
    summary.className = 'admin-row';
    const summaryLabel = document.createElement('div');
    summaryLabel.style.minWidth = '180px';
    const summaryStrong = document.createElement('strong');
    summaryStrong.textContent = 'Overall result';
    summaryLabel.appendChild(summaryStrong);
    const summaryValue = document.createElement('div');
    summaryValue.textContent = result.ok ? 'Passed' : 'Failed';
    summary.appendChild(summaryLabel);
    summary.appendChild(summaryValue);
    el.externalTestingOutput.appendChild(summary);

    const detailRows = [
      ['Subsite URL', result.subsite_url || '—'],
      ['Duration', typeof result.duration === 'number' ? `${(result.duration / 1000).toFixed(1)}s` : '—'],
    ];
    detailRows.forEach(([label, value]) => {
      const row = document.createElement('div');
      row.className = 'admin-row';
      const labelWrap = document.createElement('div');
      labelWrap.style.minWidth = '180px';
      const strong = document.createElement('strong');
      strong.textContent = label;
      labelWrap.appendChild(strong);
      const valueWrap = document.createElement('div');
      valueWrap.textContent = value;
      row.appendChild(labelWrap);
      row.appendChild(valueWrap);
      el.externalTestingOutput.appendChild(row);
    });

    const scenarioResults = result?.test_results?.cli_tests?.results || [];
    if (scenarioResults.length) {
      scenarioResults.forEach((scenario) => {
        const row = document.createElement('div');
        row.className = 'admin-row';
        const labelWrap = document.createElement('div');
        labelWrap.style.minWidth = '180px';
        const strong = document.createElement('strong');
        strong.textContent = scenario.name || 'Scenario';
        labelWrap.appendChild(strong);
        const valueWrap = document.createElement('div');
        valueWrap.textContent = scenario.status === 'passed' ? 'Passed' : 'Failed';
        if (scenario.status !== 'passed') {
          valueWrap.style.color = 'var(--danger)';
        }
        row.appendChild(labelWrap);
        row.appendChild(valueWrap);
        el.externalTestingOutput.appendChild(row);
      });
    }

    const errors = Array.isArray(result.errors) ? result.errors : [];
    if (errors.length) {
      errors.forEach((err) => {
        const row = document.createElement('div');
        row.className = 'admin-row';
        const labelWrap = document.createElement('div');
        labelWrap.style.minWidth = '180px';
        const strong = document.createElement('strong');
        strong.textContent = 'Error';
        labelWrap.appendChild(strong);
        const valueWrap = document.createElement('div');
        valueWrap.textContent = err;
        valueWrap.style.color = 'var(--danger)';
        row.appendChild(labelWrap);
        row.appendChild(valueWrap);
        el.externalTestingOutput.appendChild(row);
      });
    }
  }

  async function loadExternalTestingStatus() {
    const data = await api('/api/admin/external-testing-status');
    renderExternalTestingConfig(data.config || {});
  }

  // --- Ollama Test UI ---
  function setOllamaTestStatus(msg, isError = false) {
    if (!el.ollamaTestStatus) return;
    el.ollamaTestStatus.textContent = msg || '';
    el.ollamaTestStatus.style.color = isError ? 'var(--danger)' : 'inherit';
  }

  function renderOllamaTestOutput(data) {
    if (!el.ollamaTestOutput) return;
    el.ollamaTestOutput.innerHTML = '';
    if (!data) return;

    // Config section
    const configSection = document.createElement('div');
    configSection.style.marginBottom = '16px';
    configSection.style.padding = '12px';
    configSection.style.background = 'var(--surface)';
    configSection.style.borderRadius = '6px';
    
    const configTitle = document.createElement('div');
    configTitle.style.fontWeight = '600';
    configTitle.style.marginBottom = '8px';
    configTitle.textContent = 'Configuration';
    configSection.appendChild(configTitle);

    const configRows = [
      ['URL', data.config?.url || '—'],
      ['Model', data.config?.model || '—'],
      ['API Key Configured', data.config?.apiKeyConfigured ? 'Yes' : 'No'],
      ['API Key Preview', data.config?.apiKeyPreview || '—'],
    ];

    configRows.forEach(([label, value]) => {
      const row = document.createElement('div');
      row.className = 'admin-row';
      row.style.marginBottom = '4px';
      const labelWrap = document.createElement('div');
      labelWrap.style.minWidth = '140px';
      labelWrap.style.fontSize = '12px';
      labelWrap.style.color = 'var(--muted)';
      labelWrap.textContent = label;
      const valueWrap = document.createElement('div');
      valueWrap.style.fontSize = '12px';
      valueWrap.textContent = value;
      row.appendChild(labelWrap);
      row.appendChild(valueWrap);
      configSection.appendChild(row);
    });

    el.ollamaTestOutput.appendChild(configSection);

    // Result section
    if (data.result) {
      const resultSection = document.createElement('div');
      resultSection.style.marginBottom = '16px';
      resultSection.style.padding = '12px';
      resultSection.style.background = 'rgba(0, 200, 0, 0.1)';
      resultSection.style.borderRadius = '6px';
      resultSection.style.border = '1px solid var(--shopify-green)';

      const resultTitle = document.createElement('div');
      resultTitle.style.fontWeight = '600';
      resultTitle.style.marginBottom = '8px';
      resultTitle.style.color = 'var(--shopify-green)';
      resultTitle.textContent = `✓ Test Passed (${data.duration}ms)`;
      resultSection.appendChild(resultTitle);

      const resultRows = [
        ['Response', data.result.reply || '—'],
        ['Model Used', data.result.model || '—'],
      ];

      resultRows.forEach(([label, value]) => {
        const row = document.createElement('div');
        row.className = 'admin-row';
        row.style.marginBottom = '4px';
        const labelWrap = document.createElement('div');
        labelWrap.style.minWidth = '140px';
        labelWrap.style.fontSize = '12px';
        labelWrap.style.color = 'var(--muted)';
        labelWrap.textContent = label;
        const valueWrap = document.createElement('div');
        valueWrap.style.fontSize = '12px';
        valueWrap.textContent = value;
        row.appendChild(labelWrap);
        row.appendChild(valueWrap);
        resultSection.appendChild(row);
      });

      el.ollamaTestOutput.appendChild(resultSection);
    }

    // Error section
    if (data.error) {
      const errorSection = document.createElement('div');
      errorSection.style.marginBottom = '16px';
      errorSection.style.padding = '12px';
      errorSection.style.background = 'rgba(255, 0, 0, 0.05)';
      errorSection.style.borderRadius = '6px';
      errorSection.style.border = '1px solid var(--danger)';

      const errorTitle = document.createElement('div');
      errorTitle.style.fontWeight = '600';
      errorTitle.style.marginBottom = '8px';
      errorTitle.style.color = 'var(--danger)';
      errorTitle.textContent = `✗ Test Failed (${data.duration}ms)`;
      errorSection.appendChild(errorTitle);

      const errorRows = [
        ['Error Message', data.error.message || '—'],
        ['Status Code', data.error.status || '—'],
        ['Detail', data.error.detail || '—'],
        ['Auth Error', data.error.isAuthError ? 'Yes' : 'No'],
        ['Model Missing', data.error.isModelMissing ? 'Yes' : 'No'],
        ['Error Code', data.error.code || '—'],
      ];

      errorRows.forEach(([label, value]) => {
        const row = document.createElement('div');
        row.className = 'admin-row';
        row.style.marginBottom = '4px';
        const labelWrap = document.createElement('div');
        labelWrap.style.minWidth = '140px';
        labelWrap.style.fontSize = '12px';
        labelWrap.style.color = 'var(--muted)';
        labelWrap.textContent = label;
        const valueWrap = document.createElement('div');
        valueWrap.style.fontSize = '12px';
        valueWrap.style.color = label === 'Error Message' ? 'var(--danger)' : 'inherit';
        valueWrap.textContent = value;
        row.appendChild(labelWrap);
        row.appendChild(valueWrap);
        errorSection.appendChild(row);
      });

      el.ollamaTestOutput.appendChild(errorSection);
    }
  }

  async function api(path, options = {}) {
    const res = await fetch(path, {
      credentials: 'same-origin',
      headers: { 'Content-Type': 'application/json', ...(options.headers || {}) },
      ...options,
    });
    const text = await res.text();
    const data = text ? JSON.parse(text) : {};
    if (res.status === 401) {
      window.location.href = '/admin/login';
      throw new Error('Unauthorized');
    }
    if (!res.ok) throw new Error(data.error || res.statusText);
    return data;
  }

  function parseProviderOrderInput(raw, fallbackModel) {
    const input = (raw || '').trim();
    if (!input) return [];
    const parts = input.split(',').map((p) => p.trim()).filter(Boolean);
    return parts.map((part, idx) => {
      const segments = part.split(':').map((s) => s.trim());
      const provider = segments[0];
      const model = segments[1] || fallbackModel || provider;
      if (!provider) return null;
      return { provider, model, primary: idx === 0 };
    }).filter(Boolean).map((p, idx) => ({ ...p, primary: idx === 0 }));
  }

  function renderAvailable() {
    if (!el.availableModels) return;
    el.availableModels.innerHTML = '';
    if (!state.available.length) {
      const opt = document.createElement('option');
      opt.value = '';
      opt.textContent = 'No models discovered';
      opt.disabled = true;
      opt.selected = true;
      el.availableModels.appendChild(opt);
      return;
    }
    state.available.forEach((m) => {
      const opt = document.createElement('option');
      opt.value = m.name || m.id || m;
      opt.textContent = m.label || m.name || m.id || m;
      el.availableModels.appendChild(opt);
    });
    if (!el.displayLabel.value) {
      const first = state.available[0];
      if (first) el.displayLabel.value = first.label || first.name || '';
    }
  }

  function renderIcons() {
    // Populate legacy icon select
    if (el.iconSelect) {
      el.iconSelect.innerHTML = '';
      const none = document.createElement('option');
      none.value = '';
      none.textContent = 'No icon';
      el.iconSelect.appendChild(none);
      state.icons.forEach((iconPath) => {
        const opt = document.createElement('option');
        opt.value = iconPath;
        opt.textContent = iconPath.replace('/assets/', '');
        el.iconSelect.appendChild(opt);
      });
    }
    
    // Populate OpenCode model icon select
    if (el.opencodeModelIcon) {
      el.opencodeModelIcon.innerHTML = '';
      const none = document.createElement('option');
      none.value = '';
      none.textContent = 'No icon';
      el.opencodeModelIcon.appendChild(none);
      state.icons.forEach((iconPath) => {
        const opt = document.createElement('option');
        opt.value = iconPath;
        opt.textContent = iconPath.replace('/assets/', '');
        el.opencodeModelIcon.appendChild(opt);
      });
    }
    
    // Populate public model icon select
    if (el.publicModelIcon) {
      el.publicModelIcon.innerHTML = '';
      const none = document.createElement('option');
      none.value = '';
      none.textContent = 'No icon';
      el.publicModelIcon.appendChild(none);
      state.icons.forEach((iconPath) => {
        const opt = document.createElement('option');
        opt.value = iconPath;
        opt.textContent = iconPath.replace('/assets/', '');
        el.publicModelIcon.appendChild(opt);
      });
    }

    if (el.iconList) {
      el.iconList.innerHTML = '';
      if (!state.icons.length) {
        const div = document.createElement('div');
        div.className = 'muted';
        div.textContent = 'Add icons to /chat/public/assets to see them here.';
        el.iconList.appendChild(div);
        return;
      }
      state.icons.forEach((iconPath) => {
        const row = document.createElement('div');
        row.className = 'admin-row';
        const chip = document.createElement('div');
        chip.className = 'model-chip';
        const img = document.createElement('img');
        img.src = iconPath;
        img.alt = '';
        chip.appendChild(img);
        const span = document.createElement('span');
        span.textContent = iconPath.replace('/assets/', '');
        chip.appendChild(span);
        row.appendChild(chip);
        el.iconList.appendChild(row);
      });
    }
  }

  // Render OpenCode models list with up/down ordering
  function renderOpencodeModels() {
    if (!el.opencodeModelsList) return;
    el.opencodeModelsList.innerHTML = '';
    if (el.opencodeModelsCount) el.opencodeModelsCount.textContent = state.opencodeModels.length.toString();
    
    if (!state.opencodeModels.length) {
      const empty = document.createElement('div');
      empty.className = 'muted';
      empty.textContent = 'No OpenCode models configured. Add models to enable fallback chain for build execution.';
      el.opencodeModelsList.appendChild(empty);
      return;
    }

    state.opencodeModels.forEach((m, idx) => {
      const row = document.createElement('div');
      row.className = 'provider-row slim';

      const header = document.createElement('div');
      header.className = 'provider-row-header';
      
      const info = document.createElement('div');
      info.className = 'model-chip';
      
      // Priority badge
      const order = document.createElement('span');
      order.className = 'pill';
      order.textContent = idx === 0 ? 'Primary' : `#${idx + 1}`;
      if (idx === 0) order.style.background = 'var(--shopify-green)';
      info.appendChild(order);
      
      if (m.icon) {
        const img = document.createElement('img');
        img.src = m.icon;
        img.alt = '';
        info.appendChild(img);
      }
      
      const label = document.createElement('span');
      label.textContent = m.label || m.name;
      info.appendChild(label);
      
      const namePill = document.createElement('span');
      namePill.className = 'pill';
      namePill.textContent = m.name;
      info.appendChild(namePill);
      
      const tierMeta = document.createElement('span');
      tierMeta.className = 'pill';
      const tierName = (m.tier || 'free').toUpperCase();
      const multiplier = m.tier === 'pro' ? 3 : (m.tier === 'plus' ? 2 : 1);
      tierMeta.textContent = `${tierName} (${multiplier}x)`;
      info.appendChild(tierMeta);
      
      if (m.supportsMedia) {
        const mediaBadge = document.createElement('span');
        mediaBadge.className = 'pill';
        mediaBadge.style.background = 'var(--shopify-green)';
        mediaBadge.textContent = 'Media';
        info.appendChild(mediaBadge);
      }
      
      header.appendChild(info);

      const headerActions = document.createElement('div');
      headerActions.className = 'provider-row-actions';

      // Up button
      const upBtn = document.createElement('button');
      upBtn.className = 'ghost';
      upBtn.textContent = '↑';
      upBtn.title = 'Move up';
      upBtn.disabled = idx === 0;
      upBtn.addEventListener('click', async () => {
        const next = [...state.opencodeModels];
        const [item] = next.splice(idx, 1);
        next.splice(Math.max(0, idx - 1), 0, item);
        await persistOpencodeModelsOrder(next);
      });
      headerActions.appendChild(upBtn);

      // Down button
      const downBtn = document.createElement('button');
      downBtn.className = 'ghost';
      downBtn.textContent = '↓';
      downBtn.title = 'Move down';
      downBtn.disabled = idx === state.opencodeModels.length - 1;
      downBtn.addEventListener('click', async () => {
        const next = [...state.opencodeModels];
        const [item] = next.splice(idx, 1);
        next.splice(Math.min(state.opencodeModels.length, idx + 1), 0, item);
        await persistOpencodeModelsOrder(next);
      });
      headerActions.appendChild(downBtn);

      const delBtn = document.createElement('button');
      delBtn.className = 'ghost';
      delBtn.textContent = 'Delete';
      delBtn.addEventListener('click', async () => {
        delBtn.disabled = true;
        try {
          await api(`/api/admin/models/${m.id}?type=opencode`, { method: 'DELETE' });
          await loadConfigured();
        } catch (err) {
          setStatus(err.message, true);
        }
        delBtn.disabled = false;
      });
      headerActions.appendChild(delBtn);

      // Inline icon editor button
      const editIconBtn = document.createElement('button');
      editIconBtn.className = 'ghost';
      editIconBtn.textContent = 'Edit icon';
      editIconBtn.addEventListener('click', () => {
        let editor = header.querySelector('.icon-editor');
        if (editor) return editor.remove();
        editor = document.createElement('div');
        editor.className = 'icon-editor';

        const sel = document.createElement('select');
        const none = document.createElement('option');
        none.value = '';
        none.textContent = 'No icon';
        sel.appendChild(none);
        (state.icons || []).forEach((iconPath) => {
          const o = document.createElement('option');
          o.value = iconPath;
          o.textContent = iconPath.replace('/assets/', '');
          sel.appendChild(o);
        });
        sel.value = m.icon || '';
        editor.appendChild(sel);

        const saveBtn = document.createElement('button');
        saveBtn.className = 'primary';
        saveBtn.textContent = 'Save';
        saveBtn.addEventListener('click', async () => {
          saveBtn.disabled = true;
          try {
            await persistOpencodeModelChanges(m.id, { icon: sel.value });
          } catch (err) { setStatus(err.message, true); }
          saveBtn.disabled = false;
        });
        editor.appendChild(saveBtn);

        const cancelBtn = document.createElement('button');
        cancelBtn.className = 'ghost';
        cancelBtn.textContent = 'Cancel';
        cancelBtn.addEventListener('click', () => editor.remove());
        editor.appendChild(cancelBtn);

        headerActions.appendChild(editor);
      });
      headerActions.appendChild(editIconBtn);

      // Supports media checkbox
      const mediaToggle = document.createElement('label');
      mediaToggle.style.display = 'flex';
      mediaToggle.style.alignItems = 'center';
      mediaToggle.style.gap = '6px';
      mediaToggle.style.marginLeft = '8px';
      const mediaCheckbox = document.createElement('input');
      mediaCheckbox.type = 'checkbox';
      mediaCheckbox.checked = m.supportsMedia ?? false;
      mediaCheckbox.addEventListener('change', async () => {
        mediaCheckbox.disabled = true;
        try {
          await persistOpencodeModelChanges(m.id, { supportsMedia: mediaCheckbox.checked });
        } catch (err) { setStatus(err.message, true); }
        mediaCheckbox.disabled = false;
      });
      mediaToggle.appendChild(mediaCheckbox);
      const mediaLabel = document.createElement('span');
      mediaLabel.textContent = 'Media';
      mediaLabel.style.fontSize = '12px';
      mediaLabel.style.color = 'var(--muted)';
      mediaToggle.appendChild(mediaLabel);
      headerActions.appendChild(mediaToggle);

      header.appendChild(headerActions);
      row.appendChild(header);
      el.opencodeModelsList.appendChild(row);
    });
  }

  // Render Public models list with up/down ordering
  function renderPublicModels() {
    if (!el.publicModelsList) return;
    el.publicModelsList.innerHTML = '';
    if (el.publicModelsCount) el.publicModelsCount.textContent = state.publicModels.length.toString();
    
    if (!state.publicModels.length) {
      const empty = document.createElement('div');
      empty.className = 'muted';
      empty.textContent = 'No public models configured. Add models to display them to users in the builder.';
      el.publicModelsList.appendChild(empty);
      return;
    }

    state.publicModels.forEach((m, idx) => {
      const row = document.createElement('div');
      row.className = 'provider-row slim';

      const header = document.createElement('div');
      header.className = 'provider-row-header';
      
      const info = document.createElement('div');
      info.className = 'model-chip';
      
      // Priority badge
      const order = document.createElement('span');
      order.className = 'pill';
      order.textContent = idx === 0 ? 'Primary' : `#${idx + 1}`;
      if (idx === 0) order.style.background = 'var(--shopify-green)';
      info.appendChild(order);
      
      if (m.icon) {
        const img = document.createElement('img');
        img.src = m.icon;
        img.alt = '';
        info.appendChild(img);
      }
      
      const label = document.createElement('span');
      label.textContent = m.label || m.name;
      info.appendChild(label);
      
      const namePill = document.createElement('span');
      namePill.className = 'pill';
      namePill.textContent = m.name;
      info.appendChild(namePill);
      
      const tierMeta = document.createElement('span');
      tierMeta.className = 'pill';
      const tierName = (m.tier || 'free').toUpperCase();
      const multiplier = m.tier === 'pro' ? 3 : (m.tier === 'plus' ? 2 : 1);
      tierMeta.textContent = `${tierName} (${multiplier}x)`;
      info.appendChild(tierMeta);
      
      if (m.supportsMedia) {
        const mediaBadge = document.createElement('span');
        mediaBadge.className = 'pill';
        mediaBadge.style.background = 'var(--shopify-green)';
        mediaBadge.textContent = 'Media';
        info.appendChild(mediaBadge);
      }
      
      header.appendChild(info);

      const headerActions = document.createElement('div');
      headerActions.className = 'provider-row-actions';

      // Up button
      const upBtn = document.createElement('button');
      upBtn.className = 'ghost';
      upBtn.textContent = '↑';
      upBtn.title = 'Move up';
      upBtn.disabled = idx === 0;
      upBtn.addEventListener('click', async () => {
        const next = [...state.publicModels];
        const [item] = next.splice(idx, 1);
        next.splice(Math.max(0, idx - 1), 0, item);
        await persistPublicModelsOrder(next);
      });
      headerActions.appendChild(upBtn);

      // Down button
      const downBtn = document.createElement('button');
      downBtn.className = 'ghost';
      downBtn.textContent = '↓';
      downBtn.title = 'Move down';
      downBtn.disabled = idx === state.publicModels.length - 1;
      downBtn.addEventListener('click', async () => {
        const next = [...state.publicModels];
        const [item] = next.splice(idx, 1);
        next.splice(Math.min(state.publicModels.length, idx + 1), 0, item);
        await persistPublicModelsOrder(next);
      });
      headerActions.appendChild(downBtn);

      const delBtn = document.createElement('button');
      delBtn.className = 'ghost';
      delBtn.textContent = 'Delete';
      delBtn.addEventListener('click', async () => {
        delBtn.disabled = true;
        try {
          await api(`/api/admin/models/${m.id}?type=public`, { method: 'DELETE' });
          await loadConfigured();
        } catch (err) {
          setStatus(err.message, true);
        }
        delBtn.disabled = false;
      });
      headerActions.appendChild(delBtn);

      // Inline icon editor button
      const editIconBtn = document.createElement('button');
      editIconBtn.className = 'ghost';
      editIconBtn.textContent = 'Edit icon';
      editIconBtn.addEventListener('click', () => {
        let editor = header.querySelector('.icon-editor');
        if (editor) return editor.remove();
        editor = document.createElement('div');
        editor.className = 'icon-editor';

        const sel = document.createElement('select');
        const none = document.createElement('option');
        none.value = '';
        none.textContent = 'No icon';
        sel.appendChild(none);
        (state.icons || []).forEach((iconPath) => {
          const o = document.createElement('option');
          o.value = iconPath;
          o.textContent = iconPath.replace('/assets/', '');
          sel.appendChild(o);
        });
        sel.value = m.icon || '';
        editor.appendChild(sel);

        const saveBtn = document.createElement('button');
        saveBtn.className = 'primary';
        saveBtn.textContent = 'Save';
        saveBtn.addEventListener('click', async () => {
          saveBtn.disabled = true;
          try {
            await persistPublicModelChanges(m.id, { icon: sel.value });
          } catch (err) { setStatus(err.message, true); }
          saveBtn.disabled = false;
        });
        editor.appendChild(saveBtn);

        const cancelBtn = document.createElement('button');
        cancelBtn.className = 'ghost';
        cancelBtn.textContent = 'Cancel';
        cancelBtn.addEventListener('click', () => editor.remove());
        editor.appendChild(cancelBtn);

        headerActions.appendChild(editor);
      });
      headerActions.appendChild(editIconBtn);

      // Supports media checkbox
      const mediaToggle = document.createElement('label');
      mediaToggle.style.display = 'flex';
      mediaToggle.style.alignItems = 'center';
      mediaToggle.style.gap = '6px';
      mediaToggle.style.marginLeft = '8px';
      const mediaCheckbox = document.createElement('input');
      mediaCheckbox.type = 'checkbox';
      mediaCheckbox.checked = m.supportsMedia ?? false;
      mediaCheckbox.addEventListener('change', async () => {
        mediaCheckbox.disabled = true;
        try {
          await persistPublicModelChanges(m.id, { supportsMedia: mediaCheckbox.checked });
        } catch (err) { setStatus(err.message, true); }
        mediaCheckbox.disabled = false;
      });
      mediaToggle.appendChild(mediaCheckbox);
      const mediaLabel = document.createElement('span');
      mediaLabel.textContent = 'Media';
      mediaLabel.style.fontSize = '12px';
      mediaLabel.style.color = 'var(--muted)';
      mediaToggle.appendChild(mediaLabel);
      headerActions.appendChild(mediaToggle);

      // Tier editor button
      const editTierBtn = document.createElement('button');
      editTierBtn.className = 'ghost';
      editTierBtn.textContent = 'Edit tier';
      editTierBtn.addEventListener('click', () => {
        let editor = header.querySelector('.tier-editor');
        if (editor) return editor.remove();
        editor = document.createElement('div');
        editor.className = 'tier-editor';

        const sel = document.createElement('select');
        const options = [
          { value: 'free', label: 'Free (1x)' },
          { value: 'plus', label: 'Plus (2x)' },
          { value: 'pro', label: 'Pro (3x)' }
        ];
        options.forEach((opt) => {
          const o = document.createElement('option');
          o.value = opt.value;
          o.textContent = opt.label;
          sel.appendChild(o);
        });
        sel.value = m.tier || 'free';
        editor.appendChild(sel);

        const saveBtn = document.createElement('button');
        saveBtn.className = 'primary';
        saveBtn.textContent = 'Save';
        saveBtn.addEventListener('click', async () => {
          saveBtn.disabled = true;
          try {
            await persistPublicModelChanges(m.id, { tier: sel.value });
          } catch (err) { setStatus(err.message, true); }
          saveBtn.disabled = false;
        });
        editor.appendChild(saveBtn);

        const cancelBtn = document.createElement('button');
        cancelBtn.className = 'ghost';
        cancelBtn.textContent = 'Cancel';
        cancelBtn.addEventListener('click', () => editor.remove());
        editor.appendChild(cancelBtn);

        headerActions.appendChild(editor);
      });
      headerActions.appendChild(editTierBtn);

      header.appendChild(headerActions);
      row.appendChild(header);
      el.publicModelsList.appendChild(row);
    });
  }

  // Legacy renderConfigured for backward compatibility
  function renderConfigured() {
    renderOpencodeModels();
    renderPublicModels();
  }

  async function persistOpencodeModelChanges(modelId, changes) {
    setStatus('Saving...');
    const model = state.opencodeModels.find((m) => m.id === modelId);
    if (!model) {
      setStatus('Model not found', true);
      return;
    }
    
    const payload = {
      type: 'opencode',
      id: modelId,
      name: model.name,
      label: model.label || model.name,
      icon: changes.icon !== undefined ? changes.icon : model.icon,
      tier: changes.tier !== undefined ? changes.tier : model.tier,
      supportsMedia: changes.supportsMedia !== undefined ? changes.supportsMedia : model.supportsMedia,
    };
    
    try {
      const data = await api('/api/admin/models', { method: 'POST', body: JSON.stringify(payload) });
      const idx = state.opencodeModels.findIndex((m) => m.id === modelId);
      if (idx >= 0) state.opencodeModels[idx] = { ...state.opencodeModels[idx], ...data.opencodeModel };
      renderOpencodeModels();
      setStatus('Saved');
      setTimeout(() => setStatus(''), 1500);
    } catch (err) {
      setStatus(err.message, true);
    }
  }

  async function persistOpencodeModelsOrder(nextModels) {
    setStatus('Saving order...');
    try {
      const payload = { type: 'opencode', models: nextModels.map(m => ({ id: m.id })) };
      const res = await api('/api/admin/models/reorder', { method: 'POST', body: JSON.stringify(payload) });
      state.opencodeModels = res.opencodeModels || nextModels;
      renderOpencodeModels();
      setStatus('Saved');
      setTimeout(() => setStatus(''), 1500);
    } catch (err) {
      setStatus(err.message, true);
    }
  }

  async function persistPublicModelsOrder(nextModels) {
    setStatus('Saving order...');
    try {
      const payload = { type: 'public', models: nextModels.map(m => ({ id: m.id })) };
      const res = await api('/api/admin/models/reorder', { method: 'POST', body: JSON.stringify(payload) });
      state.publicModels = res.publicModels || nextModels;
      renderPublicModels();
      setStatus('Saved');
      setTimeout(() => setStatus(''), 1500);
    } catch (err) {
      setStatus(err.message, true);
    }
  }

  async function persistPublicModelChanges(modelId, changes) {
    setStatus('Saving...');
    const model = state.publicModels.find((m) => m.id === modelId);
    if (!model) {
      setStatus('Model not found', true);
      return;
    }
    
    const payload = {
      type: 'publicModel',
      id: modelId,
      name: model.name,
      label: model.label || model.name,
      icon: changes.icon !== undefined ? changes.icon : model.icon,
      tier: changes.tier !== undefined ? changes.tier : model.tier,
      supportsMedia: changes.supportsMedia !== undefined ? changes.supportsMedia : model.supportsMedia,
    };
    
    try {
      const data = await api('/api/admin/models', { method: 'POST', body: JSON.stringify(payload) });
      const idx = state.publicModels.findIndex((m) => m.id === modelId);
      if (idx >= 0) state.publicModels[idx] = { ...state.publicModels[idx], ...data.publicModel };
      renderConfigured();
      setStatus('Saved');
      setTimeout(() => setStatus(''), 1500);
    } catch (err) {
      setStatus(err.message, true);
    }
  }

  // Render the unified provider chain with up/down controls
  function renderProviderChain() {
    if (!el.providerChainList) return;
    el.providerChainList.innerHTML = '';
    if (el.providerChainCount) el.providerChainCount.textContent = state.providerChain.length.toString();
    
    if (!state.providerChain.length) {
      const empty = document.createElement('div');
      empty.className = 'muted';
      empty.textContent = 'No provider chain configured. Add providers to enable automatic fallback.';
      el.providerChainList.appendChild(empty);
      return;
    }

    state.providerChain.forEach((entry, idx) => {
      const row = document.createElement('div');
      row.className = 'provider-row slim';

      const header = document.createElement('div');
      header.className = 'provider-row-header';
      
      const info = document.createElement('div');
      info.className = 'model-chip';
      
      // Priority badge
      const order = document.createElement('span');
      order.className = 'pill';
      order.textContent = idx === 0 ? 'Primary' : `#${idx + 1}`;
      if (idx === 0) order.style.background = 'var(--shopify-green)';
      info.appendChild(order);

      // Provider badge
      const providerPill = document.createElement('span');
      providerPill.className = 'pill';
      providerPill.textContent = entry.provider;
      providerPill.style.background = 'var(--primary)';
      info.appendChild(providerPill);

      // Model name
      const modelPill = document.createElement('span');
      modelPill.textContent = entry.model;
      info.appendChild(modelPill);

      // Limit summary
      const limitPill = document.createElement('span');
      limitPill.className = 'pill';
      limitPill.textContent = formatLimitSummary(entry.provider, entry.model);
      info.appendChild(limitPill);

      header.appendChild(info);

      // Actions
      const actions = document.createElement('div');
      actions.className = 'provider-row-actions';

      const upBtn = document.createElement('button');
      upBtn.className = 'ghost';
      upBtn.textContent = '↑';
      upBtn.title = 'Move up';
      upBtn.disabled = idx === 0;
      upBtn.addEventListener('click', async () => {
        const next = [...state.providerChain];
        const [item] = next.splice(idx, 1);
        next.splice(Math.max(0, idx - 1), 0, item);
        await persistProviderChainOrder(next);
      });
      actions.appendChild(upBtn);

      const downBtn = document.createElement('button');
      downBtn.className = 'ghost';
      downBtn.textContent = '↓';
      downBtn.title = 'Move down';
      downBtn.disabled = idx === state.providerChain.length - 1;
      downBtn.addEventListener('click', async () => {
        const next = [...state.providerChain];
        const [item] = next.splice(idx, 1);
        next.splice(Math.min(state.providerChain.length, idx + 1), 0, item);
        await persistProviderChainOrder(next);
      });
      actions.appendChild(downBtn);

      const removeBtn = document.createElement('button');
      removeBtn.className = 'ghost';
      removeBtn.textContent = 'Remove';
      removeBtn.addEventListener('click', async () => {
        if (state.providerChain.length <= 1) {
          alert('Cannot remove the last provider. Add another provider first.');
          return;
        }
        const next = state.providerChain.filter((_, i) => i !== idx);
        await persistProviderChainOrder(next);
      });
      actions.appendChild(removeBtn);

      header.appendChild(actions);
      row.appendChild(header);
      el.providerChainList.appendChild(row);
    });
  }

  async function persistProviderChainOrder(nextChain) {
    setProviderChainStatus('Saving order...');
    try {
      const payload = { type: 'providerChain', chain: nextChain };
      const res = await api('/api/admin/models', { method: 'POST', body: JSON.stringify(payload) });
      state.providerChain = res.providerChain || nextChain;
      renderProviderChain();
      setProviderChainStatus('Saved');
      setTimeout(() => setProviderChainStatus(''), 1500);
    } catch (err) {
      setProviderChainStatus(err.message, true);
    }
  }

  function normalizePlanChainLocal(chain) {
    if (!Array.isArray(chain)) return [];
    const seen = new Set();
    const out = [];
    chain.forEach((entry) => {
      const provider = (entry?.provider || '').toString().trim().toLowerCase();
      if (!PLANNING_PROVIDERS.includes(provider)) return;
      // `model` is the normalized string used at runtime; `raw` preserves the
      // exact admin input for display (e.g., "groq/compound-mini"). Prefer
      // `raw` for showing in inputs, but dedupe keys using the normalized model.
      const normalizedModel = typeof entry?.model === 'string' ? entry.model.trim() : '';
      const displayModel = (typeof entry?.raw === 'string' && entry.raw.trim()) ? entry.raw.trim() : normalizedModel;
      const key = `${provider}::${normalizedModel || '__any__'}`;
      if (seen.has(key)) return;
      seen.add(key);
      out.push({ provider, model: normalizedModel, raw: displayModel });
    });
    return out;
  }

  function planLimitSummary(provider, modelName) {
    const cfg = state.providerLimits && state.providerLimits[provider];
    if (!cfg) return 'Unlimited';
    const isPerModelScope = cfg.scope === 'model';
    const hasModelSpecificLimit = isPerModelScope && modelName && cfg.perModel && cfg.perModel[modelName];
    const target = hasModelSpecificLimit ? cfg.perModel[modelName] : cfg;
    const parts = [];
    if (target.requestsPerMinute) parts.push(`${target.requestsPerMinute}/m`);
    if (target.tokensPerMinute) parts.push(`${target.tokensPerMinute} tpm`);
    if (target.requestsPerDay) parts.push(`${target.requestsPerDay}/day`);
    if (target.tokensPerDay) parts.push(`${target.tokensPerDay} tpd`);

    if (!parts.length) {
      if (isPerModelScope && !hasModelSpecificLimit) {
        return 'No limit for this model';
      }
      return 'Unlimited';
    }

    const limitStr = parts.join(' · ');
    return hasModelSpecificLimit ? `${limitStr} (per-model)` : limitStr;
  }

  async function persistPlanChain(nextChain) {
    if (!el.planPriorityList) return;
    setPlanChainStatus('Saving...');
    try {
      const payload = { planningChain: nextChain };
      const res = await api('/api/admin/plan-settings', { method: 'POST', body: JSON.stringify(payload) });
      const normalized = normalizePlanChainLocal(res.settings?.planningChain || nextChain);
      state.planSettings = { ...state.planSettings, ...(res.settings || {}), planningChain: normalized };
      renderPlanPriority();
      setPlanChainStatus('Saved');
      setTimeout(() => setPlanChainStatus(''), 1500);
    } catch (err) {
      setPlanChainStatus(err.message, true);
    }
  }

  function renderPlanPriority() {
    if (!el.planPriorityList) return;
    const chain = normalizePlanChainLocal(state.planSettings?.planningChain || []);
    el.planPriorityList.innerHTML = '';
    if (!chain.length) {
      const empty = document.createElement('div');
      empty.className = 'muted';
      empty.textContent = 'No planning models configured. Add one to enable planning fallbacks.';
      el.planPriorityList.appendChild(empty);
    }

    chain.forEach((entry, idx) => {
      const row = document.createElement('div');
      row.className = 'provider-row slim';

      const header = document.createElement('div');
      header.className = 'provider-row-header';
      const info = document.createElement('div');
      info.className = 'model-chip';
      const order = document.createElement('span');
      order.className = 'pill';
      order.textContent = `Priority #${idx + 1}`;
      info.appendChild(order);

      const providerSelect = document.createElement('select');
      PLANNING_PROVIDERS.forEach((provider) => {
        const opt = document.createElement('option');
        opt.value = provider;
        opt.textContent = provider;
        providerSelect.appendChild(opt);
      });
      providerSelect.value = entry.provider;
      providerSelect.addEventListener('change', () => {
        const next = normalizePlanChainLocal(chain.map((c, i) => (i === idx ? { ...c, provider: providerSelect.value } : c)));
        persistPlanChain(next);
      });
      info.appendChild(providerSelect);

      const modelInput = document.createElement('input');
      modelInput.type = 'text';
      modelInput.placeholder = 'Model id (supports OpenRouter, Mistral, Google, Groq, NVIDIA)';
      // Prefer showing the exact user input (`raw`) when available, otherwise show
      // the normalized `model` value.
      modelInput.value = entry.raw || entry.model;
      modelInput.setAttribute('list', ensureAvailableDatalist().id);
      modelInput.addEventListener('blur', () => {
        const val = modelInput.value.trim();
        const next = normalizePlanChainLocal(chain.map((c, i) => (i === idx ? { ...c, model: val, raw: val } : c)));
        persistPlanChain(next);
      });
      info.appendChild(modelInput);

      const limitPill = document.createElement('span');
      limitPill.className = 'pill';
      limitPill.textContent = planLimitSummary(entry.provider, entry.model);
      info.appendChild(limitPill);

      header.appendChild(info);

      const actions = document.createElement('div');
      actions.className = 'provider-row-actions';
      const upBtn = document.createElement('button');
      upBtn.className = 'ghost';
      upBtn.textContent = '↑';
      upBtn.title = 'Move up';
      upBtn.disabled = idx === 0;
      upBtn.addEventListener('click', () => {
        const next = [...chain];
        const [item] = next.splice(idx, 1);
        next.splice(Math.max(0, idx - 1), 0, item);
        persistPlanChain(next);
      });
      actions.appendChild(upBtn);

      const downBtn = document.createElement('button');
      downBtn.className = 'ghost';
      downBtn.textContent = '↓';
      downBtn.title = 'Move down';
      downBtn.disabled = idx === chain.length - 1;
      downBtn.addEventListener('click', () => {
        const next = [...chain];
        const [item] = next.splice(idx, 1);
        next.splice(Math.min(chain.length, idx + 1), 0, item);
        persistPlanChain(next);
      });
      actions.appendChild(downBtn);

      const removeBtn = document.createElement('button');
      removeBtn.className = 'ghost';
      removeBtn.textContent = 'Remove';
      removeBtn.addEventListener('click', () => {
        const next = chain.filter((_, i) => i !== idx);
        persistPlanChain(next);
      });
      actions.appendChild(removeBtn);

      header.appendChild(actions);
      row.appendChild(header);
      el.planPriorityList.appendChild(row);
    });
  }

  function renderProviderUsage() {
    if (!el.providerUsage) return;
    el.providerUsage.innerHTML = '';
    if (!state.providerUsage.length) {
      const empty = document.createElement('div');
      empty.className = 'muted';
      empty.textContent = 'No usage recorded yet.';
      el.providerUsage.appendChild(empty);
      return;
    }

    function createUsageRow(provider, label, limits, usage) {
      const row = document.createElement('div');
      row.className = 'admin-row';
      const left = document.createElement('div');
      left.style.display = 'flex';
      left.style.flexDirection = 'column';
      left.style.minWidth = '200px';
      left.innerHTML = `<strong>${provider}</strong> <span class="pill">${label}</span>`;

      const progress = document.createElement('div');
      progress.style.display = 'flex';
      progress.style.flexDirection = 'column';
      progress.style.gap = '6px';
      progress.style.flex = '1';

      const rows = [
        ['Tokens (1m)', usage.tokensLastMinute || 0, limits.tokensPerMinute || 0],
        ['Tokens (24h)', usage.tokensLastDay || 0, limits.tokensPerDay || 0],
        ['Requests (1m)', usage.requestsLastMinute || 0, limits.requestsPerMinute || 0],
        ['Requests (24h)', usage.requestsLastDay || 0, limits.requestsPerDay || 0],
      ];

      rows.forEach(([labelText, used, limit]) => {
        const wrap = document.createElement('div');
        wrap.style.display = 'flex';
        wrap.style.flexDirection = 'column';
        const labelEl = document.createElement('div');
        labelEl.style.display = 'flex';
        labelEl.style.justifyContent = 'space-between';
        labelEl.style.fontSize = '12px';
        labelEl.innerHTML = `<span>${labelText}</span><span>${used}${limit > 0 ? ` / ${limit}` : ''}</span>`;
        wrap.appendChild(labelEl);
        if (limit > 0) {
          const barOuter = document.createElement('div');
          barOuter.style.background = 'var(--border)';
          barOuter.style.height = '6px';
          barOuter.style.borderRadius = '6px';
           const barInner = document.createElement('div');
           barInner.style.height = '6px';
           barInner.style.borderRadius = '6px';
           const pct = Math.min(100, parseFloat(((used / limit) * 100).toFixed(1)));
           barInner.style.width = `${pct}%`;
          barInner.style.background = pct > 90 ? 'var(--danger)' : 'var(--primary)';
          barOuter.appendChild(barInner);
          wrap.appendChild(barOuter);
        }
        progress.appendChild(wrap);
      });

      row.appendChild(left);
      row.appendChild(progress);
      return row;
    }

    state.providerUsage.forEach((entry) => {
      const isPerModel = entry.scope === 'model';
      const perModelLimits = entry.perModelLimits || {};
      const perModelUsage = (entry.usage && entry.usage.perModel) || {};
      const modelNames = isPerModel ? [...new Set([...Object.keys(perModelLimits), ...Object.keys(perModelUsage)])] : [];

      // If per-model scope is enabled and we have models, show them individually
      if (isPerModel && modelNames.length > 0) {
        modelNames.forEach((modelName) => {
          const limits = perModelLimits[modelName] || {};
          const usage = perModelUsage[modelName] || {};
          const row = createUsageRow(entry.provider, modelName, limits, usage);
          el.providerUsage.appendChild(row);
        });
      } else {
        // Provider-level scope or no models yet - show aggregate
        const limits = entry.limits || {};
        const usage = entry.usage || {};
        const row = createUsageRow(entry.provider, entry.scope, limits, usage);
        el.providerUsage.appendChild(row);
      }
    });
  }

  function renderProviderOptions() {
    if (!el.limitProvider) return;
    const providersFromState = Array.isArray(state.providerOptions) && state.providerOptions.length
      ? [...state.providerOptions]
      : null;
    let providers = providersFromState || Object.keys(state.providerLimits || {});
    const current = el.limitProvider.value;
    el.limitProvider.innerHTML = '';
    if (!providers.length) providers = [...DEFAULT_PROVIDERS];
    providers.forEach((provider, idx) => {
      const opt = document.createElement('option');
      opt.value = provider;
      opt.textContent = provider;
      if (provider === current || (!current && idx === 0)) opt.selected = true;
      el.limitProvider.appendChild(opt);
    });
  }

  function renderLimitModelOptions(provider) {
    // If we're on the plan page, allow free-text model entry (admins can type any model id)
    if (pageType === 'plan') {
      if (!el.limitModelInput) return;
      // show input and hide the select
      if (el.limitModel) el.limitModel.style.display = 'none';
      el.limitModelInput.style.display = '';
      // Populate datalist with discovered models to help typing
      syncAvailableModelDatalist();
      // set current value from configured per-model limit if present
      const cfg = state.providerLimits && state.providerLimits[provider] ? state.providerLimits[provider] : {};
      const modelKey = el.limitModelInput.value || '';
      // Do not overwrite user's typing; keep existing value
      if (!el.limitModelInput.value && cfg.perModel) {
        // nothing to prefill unless there's exactly one per-model configured
        const keys = Object.keys(cfg.perModel || {});
        if (keys.length === 1) el.limitModelInput.value = keys[0];
      }
      return;
    }

    if (!el.limitModel) return;
    el.limitModel.style.display = '';
    if (el.limitModelInput) el.limitModelInput.style.display = 'none';
    const current = el.limitModel.value;
    const modelsFromProvider = (state.providerModels && state.providerModels[provider]) ? state.providerModels[provider] : [];
    const combined = new Set(modelsFromProvider);
    getAvailableModelNames().forEach((m) => combined.add(m));
    const sorted = Array.from(combined).filter(Boolean).sort((a, b) => a.localeCompare(b));
    el.limitModel.innerHTML = '';
    const anyOpt = document.createElement('option');
    anyOpt.value = '';
    anyOpt.textContent = 'Any model';
    el.limitModel.appendChild(anyOpt);
    sorted.forEach((model) => {
      const opt = document.createElement('option');
      opt.value = model;
      opt.textContent = model;
      el.limitModel.appendChild(opt);
    });
    if (current && sorted.includes(current)) el.limitModel.value = current;
  }

  async function loadAvailable() {
    const data = await api('/api/admin/available-models');
    state.available = data.models || [];
    renderAvailable();
    syncAvailableModelDatalist();

    const selectedAutoModel = state.planSettings && typeof state.planSettings.freePlanModel === 'string'
      ? state.planSettings.freePlanModel
      : (el.autoModelSelect ? el.autoModelSelect.value : '');
    populateAutoModelOptions(selectedAutoModel);

    if (el.limitProvider) renderLimitModelOptions(el.limitProvider.value || 'openrouter');
  }

  async function loadIcons() {
    const data = await api('/api/admin/icons');
    state.icons = data.icons || [];
    renderIcons();
  }

  async function loadConfigured() {
    const data = await api('/api/admin/models');
    // Handle new unified structure
    state.opencodeModels = data.opencodeModels || [];
    state.publicModels = data.publicModels || [];
    state.configured = data.models || []; // Legacy support
    renderOpencodeModels();
    renderPublicModels();
    const selectedAutoModel = state.planSettings && typeof state.planSettings.freePlanModel === 'string'
      ? state.planSettings.freePlanModel
      : (el.autoModelSelect ? el.autoModelSelect.value : '');
    populateAutoModelOptions(selectedAutoModel);
    populateFreePlanModelOptions(selectedAutoModel);
    syncAvailableModelDatalist();
    if (el.limitProvider) renderLimitModelOptions(el.limitProvider.value || 'openrouter');
  }

  function populateOpencodeModelSelect() {
    if (!el.opencodeModelSelect) return;
    el.opencodeModelSelect.innerHTML = '';
    
    // Add placeholder
    const placeholder = document.createElement('option');
    placeholder.value = '';
    placeholder.textContent = '-- Select a model --';
    el.opencodeModelSelect.appendChild(placeholder);
    
    // Add available models from OpenCode
    (state.available || []).forEach((m) => {
      const opt = document.createElement('option');
      opt.value = m.name || m.id || m;
      opt.textContent = m.label || m.name || m.id || m;
      el.opencodeModelSelect.appendChild(opt);
    });
    
    // Also include any provider-specific models
    Object.values(state.providerModels || {}).forEach((arr) => {
      (arr || []).forEach((name) => {
        if (name && !el.opencodeModelSelect.querySelector(`option[value="${name}"]`)) {
          const opt = document.createElement('option');
          opt.value = name;
          opt.textContent = name;
          el.opencodeModelSelect.appendChild(opt);
        }
      });
    });
  }

  async function loadOpenRouterSettings() {
    if (!el.orForm) return;
    try {
      const data = await api('/api/admin/openrouter-settings');
      if (el.orPrimary) el.orPrimary.value = data.primaryModel || '';
      if (el.orBackup1) el.orBackup1.value = data.backupModel1 || '';
      if (el.orBackup2) el.orBackup2.value = data.backupModel2 || '';
      if (el.orBackup3) el.orBackup3.value = data.backupModel3 || '';
    } catch (err) {
      setOrStatus(err.message, true);
    }
  }

  async function loadMistralSettings() {
    if (!el.mistralForm) return;
    try {
      const data = await api('/api/admin/mistral-settings');
      if (el.mistralPrimary) el.mistralPrimary.value = data.primaryModel || '';
      if (el.mistralBackup1) el.mistralBackup1.value = data.backupModel1 || '';
      if (el.mistralBackup2) el.mistralBackup2.value = data.backupModel2 || '';
      if (el.mistralBackup3) el.mistralBackup3.value = data.backupModel3 || '';
    } catch (err) {
      setMistralStatus(err.message, true);
    }
  }

  function populateLimitForm(provider, scope = 'provider') {
    if (!el.limitProvider) return;
    const selectedProvider = provider || el.limitProvider.value || 'openrouter';
    const selectedScope = scope || el.limitScope?.value || 'provider';
    const cfg = state.providerLimits[selectedProvider] || {};
    renderLimitModelOptions(selectedProvider);
    // prefer the free-text input on the plan page
    const modelKey = (pageType === 'plan' && el.limitModelInput) ? (el.limitModelInput.value || '') : (el.limitModel ? el.limitModel.value : '');
    const target = selectedScope === 'model' && modelKey && cfg.perModel && cfg.perModel[modelKey]
      ? cfg.perModel[modelKey]
      : cfg;
    if (el.limitProvider) el.limitProvider.value = selectedProvider;
    if (el.limitScope) el.limitScope.value = selectedScope;
    if (pageType === 'plan' && el.limitModelInput) {
      el.limitModelInput.value = selectedScope === 'model' ? (modelKey || '') : '';
    } else if (el.limitModel) {
      el.limitModel.value = selectedScope === 'model' ? (modelKey || '') : '';
    }
    if (el.limitTpm) el.limitTpm.value = target.tokensPerMinute ?? '';
    if (el.limitTph) el.limitTph.value = target.tokensPerHour ?? '';
    if (el.limitTpd) el.limitTpd.value = target.tokensPerDay ?? '';
    if (el.limitRpm) el.limitRpm.value = target.requestsPerMinute ?? '';
    if (el.limitRph) el.limitRph.value = target.requestsPerHour ?? '';
    if (el.limitRpd) el.limitRpd.value = target.requestsPerDay ?? '';
    if (el.limitBackup && state.opencodeBackupModel !== undefined) el.limitBackup.value = state.opencodeBackupModel || '';
  }

  async function loadProviderLimits() {
    if (!el.providerUsage && !el.providerLimitForm) return;
    try {
      const data = await api('/api/admin/provider-limits');
      state.providerLimits = data.limits || {};
      state.providerOptions = data.providers || [];
      state.providerModels = data.providerModels || {};
      (state.providerOptions || []).forEach((provider) => {
        if (provider && !state.providerLimits[provider]) state.providerLimits[provider] = {};
      });
      DEFAULT_PROVIDERS.forEach((p) => {
        if (!state.providerLimits[p]) state.providerLimits[p] = {};
      });
      state.providerUsage = data.usage || [];
      state.opencodeBackupModel = data.opencodeBackupModel || '';
      renderProviderOptions();
      populateLimitForm(el.limitProvider ? el.limitProvider.value : 'openrouter', el.limitScope ? el.limitScope.value : 'provider');
      renderProviderUsage();
      if (el.limitBackup && state.opencodeBackupModel !== undefined) el.limitBackup.value = state.opencodeBackupModel || '';
      populateOpencodeBackupOptions(state.opencodeBackupModel);
      // refresh datalist with provider-specific models
      syncAvailableModelDatalist();
      renderPlanPriority();
    } catch (err) {
      setProviderLimitStatus(err.message, true);
    }
  }

  // --- Plan tokens UI ---
  async function loadPlanTokens() {
    if (!el.planTokensTable) return;
    try {
      const data = await api('/api/admin/plan-tokens');
      state.planTokens = data.limits || {};
      renderPlanTokens();
    } catch (err) {
      if (el.planTokensStatus) el.planTokensStatus.textContent = String(err.message || err);
    }
  }

  function renderPlanTokens() {
    if (!el.planTokensTable) return;
    el.planTokensTable.innerHTML = '';
    const plansOrder = ['hobby', 'starter', 'business', 'enterprise'];
    plansOrder.forEach((plan) => {
      const card = document.createElement('div');
      card.className = 'admin-row';
      const left = document.createElement('div');
      left.style.display = 'flex';
      left.style.flexDirection = 'column';
      left.style.minWidth = '180px';
      const title = document.createElement('strong');
      title.textContent = plan;
      left.appendChild(title);
      left.style.marginBottom = '8px';

      const input = document.createElement('input');
      input.type = 'number';
      input.min = '0';
      input.step = '1';
      input.value = (state.planTokens && typeof state.planTokens[plan] === 'number') ? String(state.planTokens[plan]) : '';
      input.dataset.plan = plan;
      input.placeholder = 'Token limit';
      input.style.width = '200px';

      const wrapper = document.createElement('div');
      wrapper.style.display = 'flex';
      wrapper.style.flexDirection = 'column';
      wrapper.style.gap = '4px';

      const label = document.createElement('div');
      label.textContent = 'Token Limit';
      label.style.fontSize = '12px';
      label.style.color = 'var(--muted)';
      wrapper.appendChild(label);
      wrapper.appendChild(input);

      card.appendChild(left);
      card.appendChild(wrapper);
      el.planTokensTable.appendChild(card);
    });
  }

  async function savePlanTokens() {
    if (!el.planTokensTable) return;
    if (el.savePlanTokens) el.savePlanTokens.disabled = true;
    if (el.planTokensStatus) el.planTokensStatus.textContent = 'Saving...';
    const rows = el.planTokensTable.querySelectorAll('input[data-plan]');
    const payload = {};
    rows.forEach((input) => {
      const plan = input.dataset.plan;
      const num = input.value ? Number(input.value) : 0;
      payload[plan] = Number.isFinite(num) ? Math.max(0, Math.round(num)) : 0;
    });
    try {
      const res = await api('/api/admin/plan-tokens', { method: 'POST', body: JSON.stringify({ limits: payload }) });
      state.planTokens = res.limits || payload;
      renderPlanTokens();
      if (el.planTokensStatus) el.planTokensStatus.textContent = 'Saved';
      setTimeout(() => { if (el.planTokensStatus) el.planTokensStatus.textContent = ''; }, 1400);
    } catch (err) {
      if (el.planTokensStatus) el.planTokensStatus.textContent = err.message || String(err);
    } finally {
      if (el.savePlanTokens) el.savePlanTokens.disabled = false;
    }
  }

  // --- Token rates UI ---
  async function loadTokenRates() {
    if (!el.tokenRateUsd && !el.tokenRateGbp && !el.tokenRateEur) return;
    try {
      const data = await api('/api/admin/token-rates');
      state.tokenRates = data.rates || {};
      renderTokenRates();
    } catch (err) {
      if (el.tokenRatesStatus) el.tokenRatesStatus.textContent = String(err.message || err);
    }
  }

  function renderTokenRates() {
    if (el.tokenRateUsd) el.tokenRateUsd.value = String(state.tokenRates?.usd ?? '');
    if (el.tokenRateGbp) el.tokenRateGbp.value = String(state.tokenRates?.gbp ?? '');
    if (el.tokenRateEur) el.tokenRateEur.value = String(state.tokenRates?.eur ?? '');
  }

  async function saveTokenRates() {
    if (!el.saveTokenRates) return;
    if (el.tokenRatesStatus) el.tokenRatesStatus.textContent = 'Saving...';
    el.saveTokenRates.disabled = true;

    const rates = {
      usd: Number(el.tokenRateUsd?.value || 0),
      gbp: Number(el.tokenRateGbp?.value || 0),
      eur: Number(el.tokenRateEur?.value || 0),
    };

    Object.keys(rates).forEach((key) => {
      const value = rates[key];
      rates[key] = Number.isFinite(value) ? Math.max(0, Math.round(value)) : 0;
    });

    try {
      const res = await api('/api/admin/token-rates', { method: 'POST', body: JSON.stringify({ rates }) });
      state.tokenRates = res.rates || rates;
      renderTokenRates();
      if (el.tokenRatesStatus) el.tokenRatesStatus.textContent = 'Saved';
      setTimeout(() => { if (el.tokenRatesStatus) el.tokenRatesStatus.textContent = ''; }, 1400);
    } catch (err) {
      if (el.tokenRatesStatus) el.tokenRatesStatus.textContent = err.message || String(err);
    } finally {
      el.saveTokenRates.disabled = false;
    }
  }

  async function loadPlanProviderSettings() {
    if (!el.planProviderForm && !el.autoModelForm && !el.planPriorityList) return;
    try {
      const data = await api('/api/admin/plan-settings');
      state.planSettings = {
        provider: 'openrouter',
        freePlanModel: '',
        planningChain: [],
        ...(data || {}),
      };
      if (el.planProvider) el.planProvider.value = state.planSettings.provider || 'openrouter';
      populateAutoModelOptions(state.planSettings.freePlanModel || '');
      populateFreePlanModelOptions(state.planSettings.freePlanModel || '');
      renderPlanPriority();
    } catch (err) {
      if (el.planProviderForm) setPlanProviderStatus(err.message, true);
      if (el.autoModelForm) setAutoModelStatus(err.message, true);
      if (el.planPriorityList) setPlanChainStatus(err.message, true);
    }
  }

  function populateAutoModelOptions(selectedValue) {
    if (!el.autoModelSelect) return;

    const normalizeTier = (tier) => {
      const normalized = String(tier || 'free').trim().toLowerCase();
      return ['free', 'plus', 'pro'].includes(normalized) ? normalized : 'free';
    };

    // Use publicModels if available, fallback to configured for legacy support
    const configured = state.publicModels.length > 0 ? state.publicModels : (Array.isArray(state.configured) ? state.configured : []);
    const configuredByName = new Map();
    configured.forEach((m) => {
      const name = (m && (m.name || m.id)) ? String(m.name || m.id).trim() : '';
      if (name) configuredByName.set(name, m);
    });

    const current = typeof selectedValue === 'string' ? selectedValue : el.autoModelSelect.value;

    el.autoModelSelect.innerHTML = '';
    const auto = document.createElement('option');
    auto.value = '';
    auto.textContent = 'Auto (first free model)';
    el.autoModelSelect.appendChild(auto);

    const freeModels = configured
      .filter((m) => normalizeTier(m.tier) === 'free')
      .map((m) => ({
        name: (m && (m.name || m.id)) ? String(m.name || m.id).trim() : '',
        label: (m && (m.label || m.name || m.id)) ? String(m.label || m.name || m.id).trim() : '',
      }))
      .filter((m) => m.name);

    const freeGroup = document.createElement('optgroup');
    freeGroup.label = 'Free-tier models';

    const freeNames = new Set();
    freeModels
      .sort((a, b) => a.label.localeCompare(b.label))
      .forEach((m) => {
        freeNames.add(m.name);
        const opt = document.createElement('option');
        opt.value = m.name;
        opt.textContent = m.label || m.name;
        freeGroup.appendChild(opt);
      });

    const discoveredNames = getAvailableModelNames()
      .map((name) => String(name || '').trim())
      .filter(Boolean)
      .filter((name, idx, arr) => arr.indexOf(name) === idx)
      .filter((name) => !freeNames.has(name));

    const discoveredGroup = document.createElement('optgroup');
    discoveredGroup.label = 'Other discovered models';

    discoveredNames
      .sort((a, b) => a.localeCompare(b))
      .forEach((name) => {
        const configuredModel = configuredByName.get(name);
        const tier = configuredModel ? normalizeTier(configuredModel.tier) : null;
        const opt = document.createElement('option');
        opt.value = name;
        if (!configuredModel) {
          opt.textContent = `${name} (unpublished)`;
        } else {
          opt.textContent = `${name} (${tier.toUpperCase()})`;
          if (tier !== 'free') opt.disabled = true;
        }
        discoveredGroup.appendChild(opt);
      });

    const hasFree = freeGroup.children.length > 0;
    const hasDiscovered = discoveredGroup.children.length > 0;

    if (hasFree) {
      el.autoModelSelect.appendChild(freeGroup);
    }

    if (hasDiscovered) {
      el.autoModelSelect.appendChild(discoveredGroup);
    }

    if (!hasFree && !hasDiscovered) {
      const note = document.createElement('option');
      note.value = '__none__';
      note.textContent = '(No models discovered yet)';
      note.disabled = true;
      el.autoModelSelect.appendChild(note);
    }

    const currentName = (current || '').trim();
    if (currentName && !Array.from(el.autoModelSelect.options).some((opt) => opt.value === currentName)) {
      const orphan = document.createElement('option');
      orphan.value = currentName;
      orphan.textContent = `${currentName} (current selection)`;
      el.autoModelSelect.appendChild(orphan);
    }

    el.autoModelSelect.value = currentName;
  }

  function populateFreePlanModelOptions(selectedValue) {
    if (!el.freePlanModel) return;
    const current = selectedValue || el.freePlanModel.value;
    el.freePlanModel.innerHTML = '';
    const auto = document.createElement('option');
    auto.value = '';
    auto.textContent = 'Auto (use default)';
    el.freePlanModel.appendChild(auto);
    (state.configured || []).forEach((m) => {
      const opt = document.createElement('option');
      opt.value = m.name || m.id || '';
      opt.textContent = m.label || m.name || m.id || '';
      el.freePlanModel.appendChild(opt);
    });
    if (current !== undefined && current !== null) {
      el.freePlanModel.value = current;
    }
  }

  function populateOpencodeBackupOptions(selectedValue) {
    console.log('populateOpencodeBackupOptions called with:', selectedValue);
    if (!el.opencodeBackup) {
      console.log('el.opencodeBackup is null, returning early');
      return;
    }
    console.log('el.opencodeBackup found, populating...');
    const current = selectedValue || el.opencodeBackup.value;
    el.opencodeBackup.innerHTML = '';

    const allModels = new Set();
    (state.available || []).forEach((m) => {
      const name = m.name || m.id || m;
      if (name) allModels.add(name);
    });
    (state.configured || []).forEach((m) => {
      if (m.name) allModels.add(m.name);
    });
    Object.values(state.providerModels || {}).forEach((arr) => {
      (arr || []).forEach((name) => { if (name) allModels.add(name); });
    });

    console.log('Found models:', Array.from(allModels));
    const sorted = Array.from(allModels).filter(Boolean).sort((a, b) => a.localeCompare(b));

    const none = document.createElement('option');
    none.value = '';
    none.textContent = 'None (no backup)';
    el.opencodeBackup.appendChild(none);

    sorted.forEach((name) => {
      const opt = document.createElement('option');
      opt.value = name;
      opt.textContent = name;
      el.opencodeBackup.appendChild(opt);
    });

    if (current) el.opencodeBackup.value = current;
    console.log('Dropdown populated with', sorted.length + 1, 'options');
  }

  function formatDisplayDate(value) {
    if (!value) return '—';
    const date = new Date(value);
    if (Number.isNaN(date.getTime())) return '—';
    return date.toLocaleDateString(undefined, { month: 'short', day: 'numeric', year: 'numeric' });
  }

  function renderAccounts() {
    if (!el.accountsTable) return;
    el.accountsTable.innerHTML = '';
    if (el.accountsCount) el.accountsCount.textContent = `${state.accounts.length} accounts`;
    if (!state.accounts.length) {
      const row = document.createElement('tr');
      const cell = document.createElement('td');
      cell.colSpan = 9;
      cell.textContent = 'No accounts found.';
      cell.className = 'muted';
      cell.style.padding = '12px';
      row.appendChild(cell);
      el.accountsTable.appendChild(row);
      return;
    }
    state.accounts.forEach((acct) => {
      const row = document.createElement('tr');
      row.style.borderBottom = '1px solid var(--border)';
      [
        acct.email || 'Unknown',
        acct.plan || 'starter',
        acct.billingStatus || 'active',
        acct.billingEmail || '—',
        formatDisplayDate(acct.subscriptionRenewsAt),
        formatDisplayDate(acct.createdAt),
        formatDisplayDate(acct.lastLoginAt),
      ].forEach((value) => {
        const cell = document.createElement('td');
        cell.style.padding = '10px 8px';
        cell.textContent = value;
        row.appendChild(cell);
      });

      const tokenUsage = acct.tokenUsage || {};
      const tokensUsed = tokenUsage.used || 0;
      const tokensLimit = tokenUsage.limit || 0;
      const tokenOverride = tokenUsage.tokenOverride;
      const tokensDisplay = `${tokensUsed.toLocaleString()} / ${tokensLimit.toLocaleString()}${tokenOverride !== null && tokenOverride !== undefined ? ' (override)' : ''}`;
      
      const tokenCell = document.createElement('td');
      tokenCell.style.padding = '10px 8px';
      tokenCell.textContent = tokensDisplay;
      tokenCell.title = tokenOverride !== null && tokenOverride !== undefined ? `Manual override: ${tokenOverride.toLocaleString()} tokens` : 'Plan-based limit';
      row.appendChild(tokenCell);

      const actionsCell = document.createElement('td');
      actionsCell.style.padding = '10px 8px';
      actionsCell.style.display = 'flex';
      actionsCell.style.gap = '8px';
      const changeBtn = document.createElement('button');
      changeBtn.className = 'ghost';
      changeBtn.textContent = 'Change Plan';
      changeBtn.title = 'Change user plan without payment';
      changeBtn.addEventListener('click', () => changePlan(acct));
      actionsCell.appendChild(changeBtn);
      
      const tokensBtn = document.createElement('button');
      tokensBtn.className = 'ghost';
      tokensBtn.textContent = 'Set Tokens';
      tokensBtn.title = 'Manually set token limit for this user';
      tokensBtn.addEventListener('click', () => setTokens(acct));
      actionsCell.appendChild(tokensBtn);
      
      const deleteBtn = document.createElement('button');
      deleteBtn.className = 'danger';
      deleteBtn.textContent = 'Delete';
      deleteBtn.title = 'Permanently delete user and all data';
      deleteBtn.addEventListener('click', () => deleteUser(acct));
      actionsCell.appendChild(deleteBtn);
      
      row.appendChild(actionsCell);

      el.accountsTable.appendChild(row);
    });
  }

  async function changePlan(acct) {
    const plans = ['hobby', 'starter', 'business', 'enterprise'];
    const currentPlan = acct.plan || 'hobby';
    const nextPlan = prompt(`Change plan for ${acct.email}\nCurrent plan: ${currentPlan}\n\nEnter new plan (hobby, starter, business, enterprise):`, currentPlan);

    if (nextPlan === null) return;
    const normalized = nextPlan.trim().toLowerCase();
    if (!plans.includes(normalized)) {
      alert('Invalid plan. Please enter hobby, starter, business, or enterprise.');
      return;
    }
    if (normalized === currentPlan) return;

    if (!confirm(`Are you sure you want to change ${acct.email}'s plan to ${normalized.toUpperCase()}? This will take effect immediately without charging them.`)) {
      return;
    }

    setStatus(`Updating plan for ${acct.email}...`);
    try {
      await api('/api/admin/accounts/plan', {
        method: 'POST',
        body: JSON.stringify({ userId: acct.id, plan: normalized })
      });
      setStatus('Plan updated successfully');
      await loadAccounts();
      setTimeout(() => setStatus(''), 3000);
    } catch (err) {
      setStatus(err.message, true);
    }
  }

  async function deleteUser(acct) {
    const confirmation = window.confirm(
      `Are you absolutely sure you want to permanently delete ${acct.email}?\n\n` +
      `This will:\n` +
      `• Delete the user account permanently\n` +
      `• Remove all their apps/sessions\n` +
      `• Delete all their workspace data\n` +
      `• This action CANNOT be undone!\n\n` +
      `Type DELETE to confirm:`
    );
    
    if (!confirmation) return;
    
    const confirmationText = window.prompt(
      'This action cannot be undone. Type DELETE to confirm permanently deleting this user:'
    );
    
    if (confirmationText !== 'DELETE') {
      alert('Deletion cancelled. You must type DELETE to confirm.');
      return;
    }
    
    setStatus(`Permanently deleting ${acct.email}...`);
    try {
      await api('/api/admin/accounts', {
        method: 'DELETE',
        body: JSON.stringify({ userId: acct.id })
      });
      setStatus('User permanently deleted');
      await loadAccounts();
      setTimeout(() => setStatus(''), 3000);
    } catch (err) {
      setStatus(err.message, true);
    }
  }

  async function setTokens(acct) {
    const tokenUsage = acct.tokenUsage || {};
    const currentLimit = tokenUsage.limit || 0;
    const currentUsed = tokenUsage.used || 0;
    const currentRemaining = tokenUsage.remaining || 0;
    const hasOverride = tokenUsage.tokenOverride !== null && tokenUsage.tokenOverride !== undefined;
    const currentOverride = hasOverride ? tokenUsage.tokenOverride : '';
    
    const modeMessage = `Manage tokens for ${acct.email}\n\n` +
      `Current Status:\n` +
      `  Plan: ${acct.plan || 'starter'}\n` +
      `  Limit: ${currentLimit.toLocaleString()} tokens\n` +
      `  Used: ${currentUsed.toLocaleString()} tokens\n` +
      `  Remaining: ${currentRemaining.toLocaleString()} tokens\n` +
      `${hasOverride ? `  Override: ${currentOverride.toLocaleString()} tokens\n` : ''}\n` +
      `Choose mode:\n` +
      `  1 = Set LIMIT (override plan limit)\n` +
      `  2 = Set USED (directly set tokens consumed)\n` +
      `  3 = Set REMAINING (set tokens left to use)`;
    
    const modeInput = prompt(modeMessage, '1');
    if (modeInput === null) return;
    
    const mode = parseInt(modeInput.trim(), 10);
    if (![1, 2, 3].includes(mode)) {
      alert('Invalid mode. Please enter 1, 2, or 3.');
      return;
    }
    
    let promptText = '';
    let defaultValue = '';
    let confirmText = '';
    
    if (mode === 1) {
      promptText = `Set token LIMIT for ${acct.email}\n\n` +
        `Current limit: ${currentLimit.toLocaleString()} tokens\n` +
        `${hasOverride ? `Current override: ${currentOverride.toLocaleString()}\n` : ''}\n` +
        `Enter new limit (0 to remove override):`;
      defaultValue = currentOverride;
    } else if (mode === 2) {
      promptText = `Set tokens USED for ${acct.email}\n\n` +
        `Current used: ${currentUsed.toLocaleString()} tokens\n` +
        `Limit: ${currentLimit.toLocaleString()} tokens\n\n` +
        `Enter new usage amount:`;
      defaultValue = currentUsed;
    } else {
      promptText = `Set tokens REMAINING for ${acct.email}\n\n` +
        `Current remaining: ${currentRemaining.toLocaleString()} tokens\n` +
        `Limit: ${currentLimit.toLocaleString()} tokens\n\n` +
        `Enter remaining tokens (will calculate usage):`;
      defaultValue = currentRemaining;
    }
    
    const tokenInput = prompt(promptText, String(defaultValue));
    if (tokenInput === null) return;
    
    const tokens = parseInt(tokenInput.trim(), 10);
    if (isNaN(tokens) || tokens < 0) {
      alert('Invalid token amount. Please enter a non-negative number.');
      return;
    }
    
    if (mode === 1) {
      confirmText = `Set ${acct.email}'s token LIMIT to ${tokens.toLocaleString()}?`;
    } else if (mode === 2) {
      confirmText = `Set ${acct.email}'s tokens USED to ${tokens.toLocaleString()}?`;
    } else {
      confirmText = `Set ${acct.email}'s tokens REMAINING to ${tokens.toLocaleString()}?`;
    }
    
    if (!confirm(confirmText)) {
      return;
    }
    
    const modeNames = { 1: 'limit', 2: 'usage', 3: 'remaining' };
    setStatus(`Updating ${modeNames[mode]} for ${acct.email}...`);
    try {
      await api('/api/admin/accounts/tokens', {
        method: 'POST',
        body: JSON.stringify({ userId: acct.id, tokens: tokens, mode: modeNames[mode] })
      });
      setStatus(`Token ${modeNames[mode]} updated successfully`);
      await loadAccounts();
      setTimeout(() => setStatus(''), 3000);
    } catch (err) {
      setStatus(err.message, true);
    }
  }

  async function loadAccounts() {
    if (!el.accountsTable) return;
    setStatus('Loading accounts...');
    try {
      const data = await api('/api/admin/accounts');
      state.accounts = data.accounts || [];
      renderAccounts();
      setStatus('');
    } catch (err) {
      setStatus(err.message, true);
    }
  }

  function renderAffiliates() {
    if (!el.affiliatesTable) return;
    el.affiliatesTable.innerHTML = '';
    if (el.affiliatesCount) el.affiliatesCount.textContent = `${state.affiliates.length} affiliates`;
    if (!state.affiliates.length) {
      const row = document.createElement('tr');
      const cell = document.createElement('td');
      cell.colSpan = 8;
      cell.textContent = 'No affiliate accounts found.';
      cell.className = 'muted';
      cell.style.padding = '12px';
      row.appendChild(cell);
      el.affiliatesTable.appendChild(row);
      return;
    }
    state.affiliates.forEach((aff) => {
      const row = document.createElement('tr');
      row.style.borderBottom = '1px solid var(--border)';

      const emailCell = document.createElement('td');
      emailCell.style.padding = '10px 8px';
      emailCell.textContent = aff.email || 'Unknown';
      row.appendChild(emailCell);

      const nameCell = document.createElement('td');
      nameCell.style.padding = '10px 8px';
      nameCell.textContent = aff.name || '—';
      row.appendChild(nameCell);

      const commissionCell = document.createElement('td');
      commissionCell.style.padding = '10px 8px';
      commissionCell.textContent = `${((aff.commissionRate ?? 0.075) * 100).toFixed(1)}%`;
      row.appendChild(commissionCell);

      const earningsCell = document.createElement('td');
      earningsCell.style.padding = '10px 8px';
      const earningsTotal = aff.earnings?.total || 0;
      earningsCell.textContent = `$${earningsTotal.toFixed(2)}`;
      row.appendChild(earningsCell);

      const linksCell = document.createElement('td');
      linksCell.style.padding = '10px 8px';
      const linksCount = Array.isArray(aff.trackingLinks) ? aff.trackingLinks.length : 0;
      linksCell.textContent = linksCount > 0 ? `${linksCount} link${linksCount > 1 ? 's' : ''}` : '—';
      row.appendChild(linksCell);

      const createdCell = document.createElement('td');
      createdCell.style.padding = '10px 8px';
      createdCell.textContent = formatDisplayDate(aff.createdAt);
      row.appendChild(createdCell);

      const lastLoginCell = document.createElement('td');
      lastLoginCell.style.padding = '10px 8px';
      lastLoginCell.textContent = formatDisplayDate(aff.lastLoginAt);
      row.appendChild(lastLoginCell);

      const actionsCell = document.createElement('td');
      actionsCell.style.padding = '10px 8px';
      actionsCell.style.display = 'flex';
      actionsCell.style.gap = '8px';

      const viewLinksBtn = document.createElement('button');
      viewLinksBtn.className = 'ghost';
      viewLinksBtn.textContent = 'View Links';
      viewLinksBtn.title = 'View tracking links';
      viewLinksBtn.addEventListener('click', () => viewAffiliateLinks(aff));
      actionsCell.appendChild(viewLinksBtn);

      const deleteBtn = document.createElement('button');
      deleteBtn.className = 'danger';
      deleteBtn.textContent = 'Delete';
      deleteBtn.title = 'Permanently delete affiliate account';
      deleteBtn.addEventListener('click', () => deleteAffiliate(aff));
      actionsCell.appendChild(deleteBtn);

      row.appendChild(actionsCell);

      el.affiliatesTable.appendChild(row);
    });
  }

  function viewAffiliateLinks(aff) {
    if (!aff.trackingLinks || !aff.trackingLinks.length) {
      alert('No tracking links for this affiliate.');
      return;
    }
    const linksList = aff.trackingLinks.map(l => `${l.code} → ${l.targetPath || '/'}`).join('\n');
    alert(`Tracking links for ${aff.email}:\n\n${linksList}`);
  }

  async function deleteAffiliate(aff) {
    const confirmation = window.confirm(
      `Are you absolutely sure you want to permanently delete affiliate ${aff.email}?\n\n` +
      `This will:\n` +
      `• Delete the affiliate account permanently\n` +
      `• All tracking links will stop working\n` +
      `• Commission tracking for past referrals will remain\n` +
      `• This action CANNOT be undone!\n\n` +
      `Type DELETE to confirm:`
    );

    if (!confirmation) return;

    const confirmationText = window.prompt(
      'This action cannot be undone. Type DELETE to confirm permanently deleting this affiliate:'
    );

    if (confirmationText !== 'DELETE') {
      alert('Deletion cancelled. You must type DELETE to confirm.');
      return;
    }

    setStatus(`Permanently deleting affiliate ${aff.email}...`);
    try {
      await api('/api/admin/affiliates', {
        method: 'DELETE',
        body: JSON.stringify({ affiliateId: aff.id })
      });
      setStatus('Affiliate permanently deleted');
      await loadAffiliates();
      setTimeout(() => setStatus(''), 3000);
    } catch (err) {
      setStatus(err.message, true);
    }
  }

  async function loadAffiliates() {
    if (!el.affiliatesTable) return;
    setStatus('Loading affiliates...');
    try {
      const data = await api('/api/admin/affiliates');
      state.affiliates = data.affiliates || [];
      renderAffiliates();
      setStatus('');
    } catch (err) {
      setStatus(err.message, true);
    }
  }

  async function loadWithdrawals() {
    if (!el.withdrawalsTable) return;
    setStatus('Loading withdrawals...');
    try {
      const data = await api('/api/admin/withdrawals');
      state.withdrawals = data.withdrawals || [];
      renderWithdrawals();
      setStatus('');
    } catch (err) {
      setStatus(err.message, true);
    }
  }

  function renderWithdrawals() {
    if (!el.withdrawalsTable) return;
    el.withdrawalsTable.innerHTML = '';
    if (el.withdrawalsCount) el.withdrawalsCount.textContent = `${state.withdrawals.length} requests`;
    if (!state.withdrawals.length) {
      const row = document.createElement('tr');
      const cell = document.createElement('td');
      cell.colSpan = 7;
      cell.textContent = 'No withdrawal requests found.';
      cell.className = 'muted';
      cell.style.padding = '12px';
      row.appendChild(cell);
      el.withdrawalsTable.appendChild(row);
      return;
    }
    state.withdrawals.forEach((w) => {
      const row = document.createElement('tr');
      row.style.borderBottom = '1px solid var(--border)';

      const dateCell = document.createElement('td');
      dateCell.style.padding = '10px 8px';
      dateCell.textContent = formatDisplayDate(w.createdAt);
      row.appendChild(dateCell);

      const affiliateCell = document.createElement('td');
      affiliateCell.style.padding = '10px 8px';
      affiliateCell.textContent = w.affiliateEmail || 'Unknown';
      row.appendChild(affiliateCell);

      const paypalCell = document.createElement('td');
      paypalCell.style.padding = '10px 8px';
      paypalCell.textContent = w.paypalEmail || '—';
      row.appendChild(paypalCell);

      const amountCell = document.createElement('td');
      amountCell.style.padding = '10px 8px';
      amountCell.textContent = `$${Number(w.amount || 0).toFixed(2)}`;
      row.appendChild(amountCell);

      const currencyCell = document.createElement('td');
      currencyCell.style.padding = '10px 8px';
      currencyCell.textContent = w.currency || 'USD';
      row.appendChild(currencyCell);

      const statusCell = document.createElement('td');
      statusCell.style.padding = '10px 8px';
      const statusBadge = document.createElement('span');
      statusBadge.className = 'pill';
      statusBadge.textContent = w.status || 'pending';
      statusBadge.style.background = w.status === 'done' ? 'var(--success)' : 'var(--warning)';
      statusCell.appendChild(statusBadge);
      row.appendChild(statusCell);

      const actionsCell = document.createElement('td');
      actionsCell.style.padding = '10px 8px';
      actionsCell.style.display = 'flex';
      actionsCell.style.gap = '8px';

      if (w.status === 'pending') {
        const markDoneBtn = document.createElement('button');
        markDoneBtn.className = 'ghost';
        markDoneBtn.textContent = 'Mark Done';
        markDoneBtn.title = 'Mark withdrawal as completed';
        markDoneBtn.addEventListener('click', () => updateWithdrawalStatus(w, 'done'));
        actionsCell.appendChild(markDoneBtn);
      }

      const detailsBtn = document.createElement('button');
      detailsBtn.className = 'ghost';
      detailsBtn.textContent = 'Details';
      detailsBtn.title = 'View withdrawal details';
      detailsBtn.addEventListener('click', () => viewWithdrawalDetails(w));
      actionsCell.appendChild(detailsBtn);

      row.appendChild(actionsCell);

      el.withdrawalsTable.appendChild(row);
    });
  }

  function viewWithdrawalDetails(w) {
    alert(`Withdrawal Details:\n\n` +
      `Date: ${new Date(w.createdAt).toLocaleString()}\n` +
      `Affiliate: ${w.affiliateEmail || 'Unknown'}\n` +
      `PayPal Email: ${w.paypalEmail || '—'}\n` +
      `Amount: $${Number(w.amount || 0).toFixed(2)}\n` +
      `Currency: ${w.currency || 'USD'}\n` +
      `Status: ${w.status || 'pending'}`);
  }

  async function updateWithdrawalStatus(withdrawal, newStatus) {
    setStatus('Updating withdrawal status...');
    try {
      await api('/api/admin/withdrawals', {
        method: 'PUT',
        body: JSON.stringify({ withdrawalId: withdrawal.id, status: newStatus })
      });
      setStatus(`Withdrawal marked as ${newStatus}`);
      await loadWithdrawals();
      setTimeout(() => setStatus(''), 3000);
    } catch (err) {
      setStatus(err.message, true);
    }
  }

  async function init() {
    console.log('init() called');
    try {
      const loaders = [
        () => ((el.availableModels || el.planPriorityList) ? loadAvailable() : null),
        () => ((el.iconSelect || el.iconList) ? loadIcons() : null),
        () => (el.configuredList ? loadConfigured() : null),
        () => (el.orForm ? loadOpenRouterSettings() : null),
        () => (el.mistralForm ? loadMistralSettings() : null),
        () => ((el.autoModelForm || el.planProviderForm || el.planPriorityList) ? loadPlanProviderSettings() : null),
        () => (el.accountsTable ? loadAccounts() : null),
        () => (el.affiliatesTable ? loadAffiliates() : null),
        () => (el.withdrawalsTable ? loadWithdrawals() : null),
        () => (el.planTokensTable ? loadPlanTokens() : null),
        () => ((el.tokenRateUsd || el.tokenRateGbp || el.tokenRateEur) ? loadTokenRates() : null),
        () => ((el.providerUsage || el.providerLimitForm) ? loadProviderLimits() : null),
        () => (el.externalTestingConfig ? loadExternalTestingStatus() : null),
      ];
      await Promise.all(loaders.map((fn) => fn()).filter(Boolean));
      // Populate opencode model select after loadAvailable() has completed
      if (el.opencodeModelSelect) {
        populateOpencodeModelSelect();
      }
      // Always try to load provider limits if not already loaded (needed for backup dropdown)
      if (!state.providerModels || Object.keys(state.providerModels).length === 0) {
        try {
          const data = await api('/api/admin/provider-limits');
          state.providerLimits = data.limits || {};
          state.providerOptions = data.providers || [];
          state.providerModels = data.providerModels || {};
          state.opencodeBackupModel = data.opencodeBackupModel || '';
        } catch (e) {
          console.warn('Failed to load provider limits for backup dropdown:', e);
        }
      }
      // Ensure opencode backup dropdown is populated
      if (el.opencodeBackup) {
        populateOpencodeBackupOptions(state.opencodeBackupModel);
      }
    } catch (err) {
      setStatus(err.message, true);
    }
  }

  // OpenCode model form handler
  if (el.opencodeModelForm) {
    el.opencodeModelForm.addEventListener('submit', async (e) => {
      e.preventDefault();
      const name = el.opencodeModelSelect.value;
      const label = el.opencodeModelLabel.value.trim();
      const icon = el.opencodeModelIcon ? el.opencodeModelIcon.value : '';
      const tier = el.opencodeModelTier ? el.opencodeModelTier.value : 'free';
      const supportsMedia = el.opencodeModelMedia ? el.opencodeModelMedia.checked : false;
      
      if (!name) {
        setOpencodeModelStatus('Please select a model.', true);
        return;
      }
      if (!label) {
        setOpencodeModelStatus('Display name is required.', true);
        return;
      }
      
      setOpencodeModelStatus('Saving...');
      try {
        await api('/api/admin/models', {
          method: 'POST',
          body: JSON.stringify({ 
            type: 'opencode',
            name, 
            label, 
            icon, 
            tier, 
            supportsMedia 
          }),
        });
        setOpencodeModelStatus('Saved');
        el.opencodeModelSelect.value = '';
        el.opencodeModelLabel.value = '';
        await loadConfigured();
      } catch (err) {
        setOpencodeModelStatus(err.message, true);
      }
    });
  }

  // Reload OpenCode models button
  if (el.reloadOpencodeModels) {
    el.reloadOpencodeModels.addEventListener('click', async () => {
      setOpencodeModelStatus('Reloading models...');
      await loadAvailable();
      populateOpencodeModelSelect();
      setOpencodeModelStatus('Models reloaded');
      setTimeout(() => setOpencodeModelStatus(''), 1500);
    });
  }

  // Public model form handler
  if (el.publicModelForm) {
    el.publicModelForm.addEventListener('submit', async (e) => {
      e.preventDefault();
      const name = el.publicModelName.value.trim();
      const label = el.publicModelLabel.value.trim();
      const icon = el.publicModelIcon ? el.publicModelIcon.value : '';
      const tier = el.publicModelTier ? el.publicModelTier.value : 'free';
      const supportsMedia = el.publicModelMedia ? el.publicModelMedia.checked : false;
      
      if (!name) {
        setPublicModelStatus('Model ID is required.', true);
        return;
      }
      if (!label) {
        setPublicModelStatus('Display name is required.', true);
        return;
      }
      
      setPublicModelStatus('Saving...');
      try {
        await api('/api/admin/models', {
          method: 'POST',
          body: JSON.stringify({ 
            type: 'public',
            name, 
            label, 
            icon, 
            tier, 
            supportsMedia 
          }),
        });
        setPublicModelStatus('Saved');
        el.publicModelName.value = '';
        el.publicModelLabel.value = '';
        await loadConfigured();
      } catch (err) {
        setPublicModelStatus(err.message, true);
      }
    });
  }

  if (el.modelForm) {
    el.modelForm.addEventListener('submit', async (e) => {
      e.preventDefault();
      const model = el.availableModels.value;
      const label = el.displayLabel.value.trim();
      const icon = el.iconSelect.value;
      const tier = el.modelTier ? el.modelTier.value : 'free';
      if (!model) {
        setStatus('Pick a model to add.', true);
        return;
      }
      if (!label) {
        setStatus('Add a display name.', true);
        return;
      }
      const providers = parseProviderOrderInput(el.providerOrder ? el.providerOrder.value : '', model);
      const supportsMedia = el.supportsMedia ? el.supportsMedia.checked : false;
      setStatus('Saving...');
      try {
        await api('/api/admin/models', {
          method: 'POST',
          body: JSON.stringify({ model, label, icon, providers, tier, supportsMedia }),
        });
        setStatus('Saved');
        await loadConfigured();
      } catch (err) {
        setStatus(err.message, true);
      }
    });
  }

  if (el.orForm) {
    el.orForm.addEventListener('submit', async (e) => {
      e.preventDefault();
      const primaryModel = el.orPrimary.value.trim();
      const backupModel1 = el.orBackup1.value.trim();
      const backupModel2 = el.orBackup2.value.trim();
      const backupModel3 = el.orBackup3.value.trim();

      if (!primaryModel) {
        setOrStatus('Primary model is required.', true);
        return;
      }

      setOrStatus('Saving...');
      try {
        await api('/api/admin/openrouter-settings', {
          method: 'POST',
          body: JSON.stringify({ primaryModel, backupModel1, backupModel2, backupModel3 }),
        });
        setOrStatus('Saved');
        setTimeout(() => setOrStatus(''), 3000);
      } catch (err) {
        setOrStatus(err.message, true);
      }
    });
  }

  if (el.mistralForm) {
    el.mistralForm.addEventListener('submit', async (e) => {
      e.preventDefault();
      const primaryModel = el.mistralPrimary.value.trim();
      const backupModel1 = el.mistralBackup1.value.trim();
      const backupModel2 = el.mistralBackup2.value.trim();
      const backupModel3 = el.mistralBackup3.value.trim();

      if (!primaryModel) {
        setMistralStatus('Primary model is required.', true);
        return;
      }

      setMistralStatus('Saving...');
      try {
        await api('/api/admin/mistral-settings', {
          method: 'POST',
          body: JSON.stringify({ primaryModel, backupModel1, backupModel2, backupModel3 }),
        });
        setMistralStatus('Saved');
        setTimeout(() => setMistralStatus(''), 3000);
      } catch (err) {
        setMistralStatus(err.message, true);
      }
    });
  }

  if (el.opencodeBackupForm) {
    el.opencodeBackupForm.addEventListener('submit', async (e) => {
      e.preventDefault();
      const opencodeBackupModel = el.opencodeBackup ? el.opencodeBackup.value.trim() : '';

      setOpencodeBackupStatus('Saving...');
      try {
        const res = await api('/api/admin/provider-limits', {
          method: 'POST',
          body: JSON.stringify({ provider: 'opencode', scope: 'provider', model: '', tokensPerMinute: '', tokensPerDay: '', requestsPerMinute: '', requestsPerDay: '', opencodeBackupModel }),
        });
        // update local state and refresh dropdowns
        state.opencodeBackupModel = res.opencodeBackupModel || opencodeBackupModel || '';
        populateOpencodeBackupOptions(state.opencodeBackupModel);
        setOpencodeBackupStatus('Saved');
        setTimeout(() => setOpencodeBackupStatus(''), 3000);
      } catch (err) {
        setOpencodeBackupStatus(err.message, true);
      }
    });
  }

  if (el.autoModelForm) {
    el.autoModelForm.addEventListener('submit', async (e) => {
      e.preventDefault();
      const freePlanModel = el.autoModelSelect ? el.autoModelSelect.value.trim() : '';

      setAutoModelStatus('Saving...');
      try {
        await api('/api/admin/plan-settings', {
          method: 'POST',
          body: JSON.stringify({ freePlanModel }),
        });
        setAutoModelStatus('Saved! Free plan users will use this model.');
        setTimeout(() => setAutoModelStatus(''), 3000);
      } catch (err) {
        setAutoModelStatus(err.message, true);
      }
    });
  }

  if (el.planProviderForm) {
    el.planProviderForm.addEventListener('submit', async (e) => {
      e.preventDefault();
      const provider = el.planProvider.value.trim();

      if (!provider || !PLANNING_PROVIDERS.includes(provider)) {
        setPlanProviderStatus('Invalid provider selected.', true);
        return;
      }

      setPlanProviderStatus('Saving...');
      try {
        await api('/api/admin/plan-settings', {
          method: 'POST',
          body: JSON.stringify({ provider }),
        });
        setPlanProviderStatus('Saved');
        setTimeout(() => setPlanProviderStatus(''), 3000);
      } catch (err) {
        setPlanProviderStatus(err.message, true);
      }
    });
  }

  if (el.addPlanRow) {
    el.addPlanRow.addEventListener('click', async () => {
      const current = normalizePlanChainLocal(state.planSettings?.planningChain || []);
      const next = [...current, { provider: state.planSettings?.provider || 'openrouter', model: '' }];
      await persistPlanChain(next);
    });
  }

  if (el.providerLimitForm) {
    el.providerLimitForm.addEventListener('submit', async (e) => {
      e.preventDefault();
      const provider = el.limitProvider.value;
      const scope = el.limitScope.value;
      const payload = {
        provider,
        scope,
        model: (pageType === 'plan' && el.limitModelInput) ? el.limitModelInput.value.trim() : el.limitModel.value.trim(),
        tokensPerMinute: Number(el.limitTpm.value || 0),
        tokensPerHour: Number(el.limitTph.value || 0),
        tokensPerDay: Number(el.limitTpd.value || 0),
        requestsPerMinute: Number(el.limitRpm.value || 0),
        requestsPerHour: Number(el.limitRph.value || 0),
        requestsPerDay: Number(el.limitRpd.value || 0),
        opencodeBackupModel: el.limitBackup ? el.limitBackup.value.trim() : '',
      };
      setProviderLimitStatus('Saving...');
      try {
        await api('/api/admin/provider-limits', { method: 'POST', body: JSON.stringify(payload) });
        setProviderLimitStatus('Saved');
        await loadProviderLimits();
        setTimeout(() => setProviderLimitStatus(''), 3000);
      } catch (err) {
        setProviderLimitStatus(err.message, true);
      }
    });
  }

  if (el.limitProvider) {
    el.limitProvider.addEventListener('change', () => {
      populateLimitForm(el.limitProvider.value, el.limitScope ? el.limitScope.value : 'provider');
    });
  }

  if (el.limitScope) {
    el.limitScope.addEventListener('change', () => {
      populateLimitForm(el.limitProvider ? el.limitProvider.value : 'openrouter', el.limitScope.value);
    });
  }

  if (el.limitModel) {
    el.limitModel.addEventListener('change', () => {
      populateLimitForm(el.limitProvider ? el.limitProvider.value : 'openrouter', el.limitScope ? el.limitScope.value : 'provider');
    });
  }

  if (el.availableModels) {
    el.availableModels.addEventListener('change', () => {
      const selected = state.available.find((m) => (m.name || m.id || m) === el.availableModels.value);
      if (selected && !el.displayLabel.value) el.displayLabel.value = selected.label || selected.name || '';
    });
  }

  if (el.reloadAvailable) {
    el.reloadAvailable.addEventListener('click', async () => {
      setStatus('Refreshing available models...');
      await loadAvailable();
      setStatus('');
    });
  }

  if (el.refresh) {
    el.refresh.addEventListener('click', async () => {
      setStatus('Refreshing...');
      await init();
      setStatus('');
    });
  }

  // Plan tokens save button
  if (el.savePlanTokens) {
    el.savePlanTokens.addEventListener('click', async () => {
      await savePlanTokens();
    });
  }

  // Token rates save button
  if (el.saveTokenRates) {
    el.saveTokenRates.addEventListener('click', async () => {
      await saveTokenRates();
    });
  }

  // Cancel all messages button
  if (el.cancelAllMessages) {
    el.cancelAllMessages.addEventListener('click', async () => {
      const confirmed = window.confirm('Are you sure you want to cancel ALL running and queued messages? This action cannot be undone.');
      if (!confirmed) return;

      el.cancelAllMessages.disabled = true;
      if (el.cancelMessagesStatus) el.cancelMessagesStatus.textContent = 'Cancelling...';

      try {
        const data = await api('/api/admin/cancel-messages', { method: 'POST' });
        if (el.cancelMessagesStatus) {
          el.cancelMessagesStatus.textContent = `Cancelled ${data.totalCancelled} messages (${data.runningCancelled} running, ${data.queuedCancelled} queued) across ${data.sessionsAffected} sessions`;
          el.cancelMessagesStatus.style.color = 'var(--accent)';
        }
        setTimeout(() => {
          if (el.cancelMessagesStatus) {
            el.cancelMessagesStatus.textContent = '';
            el.cancelMessagesStatus.style.color = 'inherit';
          }
        }, 5000);
      } catch (err) {
        if (el.cancelMessagesStatus) {
          el.cancelMessagesStatus.textContent = err.message || 'Failed to cancel messages';
          el.cancelMessagesStatus.style.color = 'var(--danger)';
        }
      } finally {
        el.cancelAllMessages.disabled = false;
      }
    });
  }

  if (el.externalTestingRun) {
    el.externalTestingRun.addEventListener('click', async () => {
      el.externalTestingRun.disabled = true;
      setExternalTestingStatus('Running self-test...');
      try {
        const data = await api('/api/admin/external-testing-self-test', { method: 'POST' });
        renderExternalTestingOutput(data.result || null);
        setExternalTestingStatus(data.result && data.result.ok ? 'Self-test passed.' : 'Self-test failed.', !data.result || !data.result.ok);
      } catch (err) {
        setExternalTestingStatus(err.message || 'Self-test failed.', true);
      } finally {
        el.externalTestingRun.disabled = false;
      }
    });
  }

  // Ollama Test button handler
  if (el.ollamaTestRun) {
    el.ollamaTestRun.addEventListener('click', async () => {
      el.ollamaTestRun.disabled = true;
      setOllamaTestStatus('Running Ollama test...');
      if (el.ollamaTestOutput) el.ollamaTestOutput.innerHTML = '';
      
      try {
        const data = await api('/api/admin/ollama-test', { method: 'POST' });
        renderOllamaTestOutput(data);
        
        if (data.ok) {
          setOllamaTestStatus(`Test passed! Response time: ${data.duration}ms`);
        } else {
          setOllamaTestStatus(`Test failed: ${data.error?.message || 'Unknown error'}`, true);
        }
      } catch (err) {
        setOllamaTestStatus(err.message || 'Test failed', true);
        if (el.ollamaTestOutput) {
          el.ollamaTestOutput.innerHTML = `<div style="color: var(--danger); padding: 12px;">Error: ${err.message || 'Request failed'}</div>`;
        }
      } finally {
        el.ollamaTestRun.disabled = false;
      }
    });
  }

  if (el.logout) {
    el.logout.addEventListener('click', async () => {
      await api('/api/admin/logout', { method: 'POST' }).catch(() => { });
      window.location.href = '/admin/login';
    });
  }

  // Mobile sidebar toggle
  const menuToggle = document.getElementById('menu-toggle');
  const closeSidebar = document.getElementById('close-sidebar');
  const sidebar = document.querySelector('.sidebar');
  const sidebarOverlay = document.querySelector('.sidebar-overlay');

  if (menuToggle && sidebar) {
    menuToggle.addEventListener('click', () => {
      sidebar.classList.toggle('active');
      if (sidebarOverlay) {
        sidebarOverlay.classList.toggle('active');
      }
      document.body.classList.toggle('sidebar-open');
    });
  }

  if (closeSidebar && sidebar) {
    closeSidebar.addEventListener('click', () => {
      sidebar.classList.remove('active');
      if (sidebarOverlay) {
        sidebarOverlay.classList.remove('active');
      }
      document.body.classList.remove('sidebar-open');
    });
  }

  // Close sidebar when clicking on overlay
  if (sidebarOverlay && sidebar) {
    sidebarOverlay.addEventListener('click', () => {
      sidebar.classList.remove('active');
      sidebarOverlay.classList.remove('active');
      document.body.classList.remove('sidebar-open');
    });
  }

  // Close sidebar when clicking outside on mobile
  document.addEventListener('click', (e) => {
    if (sidebar && sidebar.classList.contains('active')) {
      if (!sidebar.contains(e.target) && (!menuToggle || !menuToggle.contains(e.target))) {
        sidebar.classList.remove('active');
        if (sidebarOverlay) {
          sidebarOverlay.classList.remove('active');
        }
        document.body.classList.remove('sidebar-open');
      }
    }
  });

  // Highlight active link in sidebar
  try {
    const navLinks = document.querySelectorAll('.sidebar-section a');
    navLinks.forEach((a) => {
      const href = a.getAttribute('href');
      const current = window.location.pathname;
      const isMatch = href === current || (href === '/admin/build' && current === '/admin');
      if (isMatch) {
        a.classList.add('active');
        a.setAttribute('aria-current', 'page');
      }
    });
  } catch (err) { }

  if (document.readyState === 'loading') {
    document.addEventListener('DOMContentLoaded', init);
  } else {
    init();
  }
})();
