/**
 * settings.mjs — Settings panel component
 * Organized settings for General, LLM, Appearance, Voice, Ingestion, Cognitive, Advanced.
 */

import store from '../store.mjs';
import api from '../api.mjs';
import { $, createElement, icon, empty } from '../utils/dom.mjs';

let container = null;
let dirty = false;
let fieldRefs = {};
let currentVersion = '';

// ──────────────────────────────────────
// Public init
// ──────────────────────────────────────

export function init() {
  container = $('#view-settings');
  if (!container) {
    console.warn('[settings] #view-settings not found');
    return;
  }

  loadSettingsFromServer();
}

// ──────────────────────────────────────
// Data loading
// ──────────────────────────────────────

async function loadSettingsFromServer() {
  try {
    const [config, versionData] = await Promise.all([
      api.getConfig(),
      fetch('/api/version').then(r => r.json()).catch(() => ({ version: '' }))
    ]);
    store.dispatch('SET_SETTINGS', config);
    currentVersion = versionData.version || '';
  } catch (err) {
    console.error('[settings] Failed to load config:', err);
  }
  buildDOM();
  populateFromStore();
}

// ──────────────────────────────────────
// DOM construction
// ──────────────────────────────────────

// Tab definitions: id → label + builder function names
const SETTINGS_TABS = [
  { id: 'general',    label: 'General',    builders: ['buildGeneralSection'] },
  { id: 'ai',         label: 'AI',         builders: ['buildLLMSection', 'buildCognitiveSection'] },
  { id: 'appearance', label: 'Appearance', builders: ['buildAppearanceSection'] },
  { id: 'voice',      label: 'Voice',      builders: ['buildVoiceSection'] },
  { id: 'data',       label: 'Data',       builders: ['buildIngestionSection', 'buildSchedulesSection'] },
  { id: 'advanced',   label: 'Advanced',   builders: ['buildAdvancedSection'] }
];

let activeTabId = 'general';
let tabContentEl = null;
let tabBarEl = null;

function buildDOM() {
  empty(container);
  fieldRefs = {};

  const panel = createElement('div', { className: 'settings-panel' });

  // Header
  const header = createElement('div', {
    style: { display: 'flex', alignItems: 'center', gap: 'var(--space-sm)', flexShrink: '0' }
  }, [
    icon('settings', { size: 24 }),
    createElement('h2', {
      style: { margin: '0', fontSize: 'var(--font-size-xl)', color: 'var(--text-primary)' }
    }, ['Settings'])
  ]);
  panel.appendChild(header);

  // Tab bar
  tabBarEl = createElement('div', { className: 'settings-tab-bar' });
  for (const tab of SETTINGS_TABS) {
    const tabBtn = createElement('button', {
      className: `settings-tab${tab.id === activeTabId ? ' active' : ''}`,
      dataset: { tab: tab.id }
    }, [tab.label]);
    tabBtn.addEventListener('click', () => switchTab(tab.id));
    tabBarEl.appendChild(tabBtn);
  }
  panel.appendChild(tabBarEl);

  // Tab content area (scrollable)
  tabContentEl = createElement('div', { className: 'settings-tab-content' });
  renderTabContent(activeTabId);
  panel.appendChild(tabContentEl);

  // Version
  const versionEl = createElement('div', { className: 'settings-version' }, [
    `AI-Do v${currentVersion}`
  ]);
  panel.appendChild(versionEl);

  // Save bar
  const saveBar = createElement('div', { className: 'settings-save-bar' });
  const saveBtn = createElement('button', {
    className: 'glass-button glass-button-accent',
    style: { display: 'flex', alignItems: 'center', gap: 'var(--space-xs)' }
  }, [
    icon('check', { size: 16 }),
    'Save Settings'
  ]);
  saveBtn.addEventListener('click', saveSettings);
  saveBar.appendChild(saveBtn);
  panel.appendChild(saveBar);

  container.appendChild(panel);
}

function switchTab(tabId) {
  activeTabId = tabId;
  if (tabBarEl) {
    tabBarEl.querySelectorAll('.settings-tab').forEach(btn => {
      btn.classList.toggle('active', btn.dataset.tab === tabId);
    });
  }
  // Rebuild field refs for the new tab and repopulate
  fieldRefs = {};
  renderTabContent(tabId);
  populateFromStore();
}

function renderTabContent(tabId) {
  if (!tabContentEl) return;
  empty(tabContentEl);
  const tab = SETTINGS_TABS.find(t => t.id === tabId);
  if (!tab) return;

  const builderMap = {
    buildGeneralSection,
    buildLLMSection,
    buildAppearanceSection,
    buildVoiceSection,
    buildIngestionSection,
    buildCognitiveSection,
    buildSchedulesSection,
    buildAdvancedSection
  };

  for (const name of tab.builders) {
    const fn = builderMap[name];
    if (fn) tabContentEl.appendChild(fn());
  }
}

// ──────────────────────────────────────
// Section builders
// ──────────────────────────────────────

function buildGeneralSection() {
  const section = createSection('settings', 'General');

  // Name
  const nameInput = createElement('input', {
    className: 'glass-input',
    type: 'text',
    placeholder: 'Agent name',
    'aria-label': 'Agent name'
  });
  nameInput.addEventListener('input', () => onFieldChange('agentName', nameInput.value));
  fieldRefs.agentName = nameInput;
  section.appendChild(createField('Agent Name', nameInput, 'The display name of your agent'));

  // User name (for personalization + usage tracking)
  const userNameInput = createElement('input', {
    className: 'glass-input',
    type: 'text',
    placeholder: 'Your name',
    'aria-label': 'Your name',
    autocomplete: 'name'
  });
  userNameInput.addEventListener('input', () => onFieldChange('userName', userNameInput.value));
  fieldRefs.userName = userNameInput;
  section.appendChild(createField('Your Name', userNameInput, 'Used for personalization'));

  // Loop interval
  const loopInput = createElement('input', {
    className: 'glass-input',
    type: 'number',
    min: '1',
    max: '60',
    step: '1',
    placeholder: '5',
    'aria-label': 'Loop interval in minutes',
    style: { width: '120px' }
  });
  loopInput.addEventListener('input', () => onFieldChange('loopMinutes', Number(loopInput.value)));
  fieldRefs.loopMinutes = loopInput;
  section.appendChild(createField('Loop Interval', createFieldRow([
    loopInput,
    createElement('span', {
      style: { color: 'var(--text-tertiary)', fontSize: 'var(--font-size-sm)' }
    }, ['minutes'])
  ]), 'How often the agent loop runs'));

  // Daily budget
  const budgetInput = createElement('input', {
    className: 'glass-input',
    type: 'number',
    min: '0',
    step: '0.5',
    placeholder: '5.00',
    'aria-label': 'Daily budget in dollars',
    style: { width: '120px' }
  });
  budgetInput.addEventListener('input', () => onFieldChange('dailyBudget', Number(budgetInput.value)));
  fieldRefs.dailyBudget = budgetInput;
  section.appendChild(createField('Daily Budget', createFieldRow([
    createElement('span', {
      style: { color: 'var(--text-tertiary)', fontSize: 'var(--font-size-sm)' }
    }, ['$']),
    budgetInput
  ]), 'Maximum daily LLM spending'));

  // Autonomous Mode toggle
  const autonomyRow = createElement('div', { className: 'settings-field-row' });
  const autonomyLabel = createElement('span', {
    style: { flex: '1', color: 'var(--text-primary)', fontSize: 'var(--font-size-sm)' }
  }, ['Autonomous Mode']);
  const autonomyToggle = createElement('button', {
    className: 'settings-toggle',
    'aria-label': 'Toggle autonomous mode',
    role: 'switch'
  });
  autonomyToggle.addEventListener('click', () => {
    const isActive = autonomyToggle.classList.toggle('active');
    autonomyToggle.setAttribute('aria-checked', String(isActive));
    onNestedFieldChange('autonomy', 'enabled', isActive);
  });
  fieldRefs.autonomyEnabled = autonomyToggle;
  autonomyRow.appendChild(autonomyLabel);
  autonomyRow.appendChild(autonomyToggle);
  section.appendChild(createField('Autonomy', autonomyRow, 'When enabled, agent runs creative skills between user messages'));

  // Autonomy interval
  const autonomyIntervalInput = createElement('input', {
    className: 'glass-input',
    type: 'number',
    min: '5',
    max: '1440',
    step: '5',
    placeholder: '30',
    'aria-label': 'Autonomous action interval in minutes',
    style: { width: '120px' }
  });
  autonomyIntervalInput.addEventListener('input', () =>
    onNestedFieldChange('autonomy', 'intervalMinutes', Number(autonomyIntervalInput.value))
  );
  fieldRefs.autonomyIntervalMinutes = autonomyIntervalInput;
  section.appendChild(createField('Autonomy Interval', createFieldRow([
    autonomyIntervalInput,
    createElement('span', {
      style: { color: 'var(--text-tertiary)', fontSize: 'var(--font-size-sm)' }
    }, ['minutes'])
  ]), 'Minimum gap between autonomous skill runs'));

  // Notifications toggle
  const notifRow = createElement('div', { className: 'settings-field-row' });
  const notifLabel = createElement('span', {
    style: { flex: '1', color: 'var(--text-primary)', fontSize: 'var(--font-size-sm)' }
  }, ['Enable Notifications']);
  const notifToggle = createElement('button', {
    className: 'settings-toggle',
    'aria-label': 'Toggle notifications',
    role: 'switch'
  });
  notifToggle.addEventListener('click', () => {
    const isActive = notifToggle.classList.toggle('active');
    notifToggle.setAttribute('aria-checked', String(isActive));
    onNestedFieldChange('notifications', 'enabled', isActive);
  });
  fieldRefs.notificationsEnabled = notifToggle;
  notifRow.appendChild(notifLabel);
  notifRow.appendChild(notifToggle);
  section.appendChild(createField('Notifications', notifRow, 'Show desktop/browser notifications for task completion and errors'));

  // Run Setup Wizard button
  const wizardBtn = createElement('button', {
    className: 'glass-button',
    type: 'button',
    style: { marginTop: 'var(--space-sm)' }
  }, ['Run Setup Wizard']);
  wizardBtn.addEventListener('click', async () => {
    try {
      const onboarding = await import('./onboarding.mjs');
      onboarding.show();
    } catch (err) {
      console.error('[settings] Failed to load onboarding:', err);
    }
  });
  section.appendChild(createField('First-Time Setup', wizardBtn, 'Re-run the setup wizard to change your API key or provider'));

  return section;
}

function buildLLMSection() {
  const section = createSection('cpu', 'LLM');

  // Adapter
  const adapterSelect = createElement('select', {
    className: 'settings-select',
    'aria-label': 'LLM adapter'
  });
  const adapters = ['claude', 'codex', 'copilot', 'gemini', 'gergy'];
  for (const a of adapters) {
    const label = a === 'gergy' ? 'Gergy (Direct API)' : a.charAt(0).toUpperCase() + a.slice(1);
    const opt = createElement('option', { value: a }, [label]);
    adapterSelect.appendChild(opt);
  }
  fieldRefs.cli = adapterSelect;
  section.appendChild(createField('Adapter', adapterSelect, 'Which LLM backend to use'));

  // ── Gergy config section (shown when adapter = gergy) ──
  const gergyConfig = createElement('div', { className: 'settings-gergy-config' });
  gergyConfig.style.display = 'none';

  // Provider dropdown
  const providerSelect = createElement('select', {
    className: 'settings-select',
    'aria-label': 'API provider'
  });
  for (const p of ['anthropic', 'openai', 'xai', 'gemini']) {
    providerSelect.appendChild(createElement('option', { value: p }, [p.charAt(0).toUpperCase() + p.slice(1)]));
  }
  providerSelect.addEventListener('change', () => onNestedFieldChange('agentic', 'provider', providerSelect.value));
  fieldRefs.agenticProvider = providerSelect;
  gergyConfig.appendChild(createField('Provider', providerSelect, 'Which API provider to use'));

  // API key (password input with toggle)
  const apiKeyRow = createElement('div', { style: { display: 'flex', gap: 'var(--space-xs)', alignItems: 'center' } });
  const apiKeyInput = createElement('input', {
    className: 'glass-input',
    type: 'password',
    placeholder: 'sk-...',
    'aria-label': 'API key',
    style: { flex: '1' }
  });
  apiKeyInput.addEventListener('input', () => {
    // Only send if user typed a new key (not the masked placeholder)
    const val = apiKeyInput.value;
    if (val && !val.includes('****')) {
      onNestedFieldChange('agentic', 'apiKey', val);
    }
  });
  const toggleKeyBtn = createElement('button', {
    className: 'glass-button-icon',
    'aria-label': 'Toggle key visibility',
    type: 'button',
    style: { flexShrink: '0' }
  });
  toggleKeyBtn.textContent = 'Show';
  toggleKeyBtn.addEventListener('click', () => {
    const isPassword = apiKeyInput.type === 'password';
    apiKeyInput.type = isPassword ? 'text' : 'password';
    toggleKeyBtn.textContent = isPassword ? 'Hide' : 'Show';
  });
  apiKeyRow.appendChild(apiKeyInput);
  apiKeyRow.appendChild(toggleKeyBtn);
  fieldRefs.agenticApiKey = apiKeyInput;
  gergyConfig.appendChild(createField('API Key', apiKeyRow, 'Your provider API key'));

  // Base URL (optional)
  const baseUrlInput = createElement('input', {
    className: 'glass-input',
    type: 'text',
    placeholder: 'https://api.anthropic.com (optional)',
    'aria-label': 'Base URL override'
  });
  baseUrlInput.addEventListener('input', () => onNestedFieldChange('agentic', 'baseUrl', baseUrlInput.value || null));
  fieldRefs.agenticBaseUrl = baseUrlInput;
  gergyConfig.appendChild(createField('Base URL', baseUrlInput, 'Override default API endpoint'));

  section.appendChild(gergyConfig);

  // ── Connection status indicator ──
  const connectionStatus = createElement('div', {
    className: 'settings-connection-status',
    style: {
      padding: 'var(--space-sm) var(--space-md)',
      borderRadius: 'var(--radius-sm)',
      background: 'var(--glass-bg)',
      border: '1px solid var(--border-subtle)',
      fontSize: 'var(--font-size-sm)',
      color: 'var(--text-secondary)',
      marginTop: 'var(--space-xs)'
    }
  });
  fieldRefs.connectionStatus = connectionStatus;
  section.appendChild(connectionStatus);

  // Adapter change handler (show/hide gergy config + model overrides)
  adapterSelect.addEventListener('change', () => {
    onFieldChange('cli', adapterSelect.value);
    gergyConfig.style.display = adapterSelect.value === 'gergy' ? '' : 'none';
    modelOverridesEl.style.display = adapterSelect.value === 'gergy' ? 'none' : '';
  });

  // ── Model overrides (hidden when gergy selected) ──
  const modelOverridesEl = createElement('div');

  // Model overrides title
  modelOverridesEl.appendChild(createElement('div', {
    style: {
      fontSize: 'var(--font-size-sm)', fontWeight: '500', color: 'var(--text-secondary)',
      marginBottom: 'var(--space-sm)', marginTop: 'var(--space-sm)'
    }
  }, ['Model Overrides']));

  // Fast / Balanced / Powerful
  const tiers = ['fast', 'balanced', 'powerful'];
  for (const tier of tiers) {
    const input = createElement('input', {
      className: 'glass-input',
      type: 'text',
      placeholder: `Default ${tier} model`,
      'aria-label': `${tier} model override`
    });
    const key = `modelOverride_${tier}`;
    input.addEventListener('input', () => onFieldChange(key, input.value));
    fieldRefs[key] = input;
    modelOverridesEl.appendChild(createField(tier.charAt(0).toUpperCase() + tier.slice(1), input));
  }

  section.appendChild(modelOverridesEl);

  return section;
}

function buildAppearanceSection() {
  const section = createSection('moon', 'Appearance');

  // Theme toggle
  const themeRow = createElement('div', { className: 'settings-field-row' });
  const themeLabel = createElement('span', {
    style: { flex: '1', color: 'var(--text-primary)', fontSize: 'var(--font-size-sm)' }
  }, ['Dark Mode']);
  const themeToggle = createElement('button', {
    className: 'settings-toggle',
    'aria-label': 'Toggle dark mode',
    role: 'switch'
  });
  themeToggle.addEventListener('click', () => {
    const currentTheme = store.getState().ui.theme;
    const newTheme = currentTheme === 'dark' ? 'light' : 'dark';
    themeToggle.classList.toggle('active', newTheme === 'dark');
    themeToggle.setAttribute('aria-checked', String(newTheme === 'dark'));
    document.documentElement.setAttribute('data-theme', newTheme);
    store.dispatch('SET_THEME', newTheme);
    dirty = true;
  });
  fieldRefs.theme = themeToggle;
  themeRow.appendChild(themeLabel);
  themeRow.appendChild(themeToggle);
  section.appendChild(createField('Theme', themeRow));

  // Font size selector
  const fontGroup = createElement('div', { className: 'settings-font-size-group' });
  const sizes = ['small', 'medium', 'large'];
  const fontButtons = {};
  for (const size of sizes) {
    const btn = createElement('button', {
      className: 'settings-font-size-option',
      dataset: { size }
    }, [size.charAt(0).toUpperCase() + size.slice(1)]);
    btn.addEventListener('click', () => {
      for (const b of Object.values(fontButtons)) b.classList.remove('active');
      btn.classList.add('active');
      document.documentElement.setAttribute('data-font-size', size);
      onFieldChange('fontSize', size);
    });
    fontButtons[size] = btn;
    fontGroup.appendChild(btn);
  }
  fieldRefs.fontSize = fontButtons;
  section.appendChild(createField('Font Size', fontGroup));

  // Accent color presets
  const ACCENT_PRESETS = [
    { name: 'Indigo',  primary: '#6366f1', light: '#818cf8', dark: '#4f46e5', secondary: '#8b5cf6' },
    { name: 'Blue',    primary: '#3b82f6', light: '#60a5fa', dark: '#2563eb', secondary: '#6366f1' },
    { name: 'Emerald', primary: '#10b981', light: '#34d399', dark: '#059669', secondary: '#06b6d4' },
    { name: 'Rose',    primary: '#f43f5e', light: '#fb7185', dark: '#e11d48', secondary: '#ec4899' },
    { name: 'Amber',   primary: '#f59e0b', light: '#fbbf24', dark: '#d97706', secondary: '#f97316' },
    { name: 'Violet',  primary: '#8b5cf6', light: '#a78bfa', dark: '#7c3aed', secondary: '#a855f7' },
  ];
  const colorRow = createElement('div', {
    className: 'settings-color-presets',
    style: { display: 'flex', gap: 'var(--space-sm)', flexWrap: 'wrap' }
  });
  const colorButtons = [];
  for (const preset of ACCENT_PRESETS) {
    const btn = createElement('button', {
      className: 'settings-color-btn',
      'aria-label': preset.name,
      title: preset.name,
      style: {
        width: '36px', height: '36px', borderRadius: '50%', border: '3px solid transparent',
        background: `linear-gradient(135deg, ${preset.primary}, ${preset.secondary})`,
        cursor: 'pointer', transition: 'border-color 0.2s, transform 0.15s', flexShrink: '0'
      }
    });
    btn.addEventListener('mouseenter', () => { btn.style.transform = 'scale(1.12)'; });
    btn.addEventListener('mouseleave', () => { btn.style.transform = ''; });
    btn.addEventListener('click', () => {
      // Apply accent to CSS variables
      const root = document.documentElement;
      root.style.setProperty('--accent-primary', preset.primary);
      root.style.setProperty('--accent-primary-light', preset.light);
      root.style.setProperty('--accent-primary-dark', preset.dark);
      root.style.setProperty('--accent-secondary', preset.secondary);
      root.style.setProperty('--accent-gradient', `linear-gradient(135deg, ${preset.primary}, ${preset.secondary})`);
      root.style.setProperty('--accent-gradient-hover', `linear-gradient(135deg, ${preset.light}, ${preset.secondary})`);
      // Update selection ring
      colorButtons.forEach(b => { b.style.borderColor = 'transparent'; });
      btn.style.borderColor = 'var(--text-primary)';
      // Persist
      onFieldChange('accentColor', preset.name);
    });
    colorButtons.push(btn);
    colorRow.appendChild(btn);
  }
  fieldRefs.accentColor = { buttons: colorButtons, presets: ACCENT_PRESETS };
  section.appendChild(createField('Accent Color', colorRow));

  return section;
}

function buildVoiceSection() {
  const section = createSection('mic', 'Voice');

  // ── Realtime Voice Agent ──
  const voiceDivider = createElement('div', {
    style: {
      fontSize: 'var(--font-size-sm)', fontWeight: '500', color: 'var(--text-secondary)',
      marginBottom: 'var(--space-sm)', marginTop: 'var(--space-md)'
    }
  }, ['Realtime Voice Agent']);
  section.appendChild(voiceDivider);

  // Voice provider selector
  const voiceProviderSelect = createElement('select', {
    className: 'settings-select', 'aria-label': 'Voice provider'
  });
  voiceProviderSelect.appendChild(createElement('option', { value: 'xai' }, ['xAI Grok']));
  voiceProviderSelect.appendChild(createElement('option', { value: 'openai' }, ['OpenAI']));
  voiceProviderSelect.addEventListener('change', () => {
    onNestedFieldChange('voice', 'provider', voiceProviderSelect.value);
    // Show/hide provider-specific key fields
    xaiKeyField.style.display = voiceProviderSelect.value === 'xai' ? '' : 'none';
    openaiKeyField.style.display = voiceProviderSelect.value === 'openai' ? '' : 'none';
  });
  fieldRefs.voiceProvider = voiceProviderSelect;
  section.appendChild(createField('Voice Provider', voiceProviderSelect, 'AI provider for real-time voice conversations'));

  // xAI API Key (password input with show/hide toggle)
  const xaiKeyRow = createElement('div', { style: { display: 'flex', gap: 'var(--space-xs)', alignItems: 'center' } });
  const xaiKeyInput = createElement('input', {
    className: 'glass-input', type: 'password',
    placeholder: 'xai-... (optional — uses hosted proxy if blank)',
    'aria-label': 'xAI API key', style: { flex: '1' }
  });
  xaiKeyInput.addEventListener('input', () => {
    const val = xaiKeyInput.value;
    if (val && !val.includes('****')) onNestedFieldChange('voice', 'xaiApiKey', val);
  });
  const xaiKeyToggle = createElement('button', {
    className: 'glass-button-icon', 'aria-label': 'Toggle key visibility',
    type: 'button', style: { flexShrink: '0' }
  });
  xaiKeyToggle.textContent = 'Show';
  xaiKeyToggle.addEventListener('click', () => {
    const isPassword = xaiKeyInput.type === 'password';
    xaiKeyInput.type = isPassword ? 'text' : 'password';
    xaiKeyToggle.textContent = isPassword ? 'Hide' : 'Show';
  });
  xaiKeyRow.appendChild(xaiKeyInput);
  xaiKeyRow.appendChild(xaiKeyToggle);
  fieldRefs.xaiApiKey = xaiKeyInput;
  const xaiKeyField = createField('xAI API Key', xaiKeyRow, 'Your xAI key for unlimited voice usage');
  section.appendChild(xaiKeyField);

  // OpenAI API Key (password input with show/hide toggle)
  const openaiKeyRow = createElement('div', { style: { display: 'flex', gap: 'var(--space-xs)', alignItems: 'center' } });
  const openaiKeyInput = createElement('input', {
    className: 'glass-input', type: 'password',
    placeholder: 'sk-... (optional — uses hosted proxy if blank)',
    'aria-label': 'OpenAI API key', style: { flex: '1' }
  });
  openaiKeyInput.addEventListener('input', () => {
    const val = openaiKeyInput.value;
    if (val && !val.includes('****')) onNestedFieldChange('voice', 'openaiApiKey', val);
  });
  const openaiKeyToggle = createElement('button', {
    className: 'glass-button-icon', 'aria-label': 'Toggle key visibility',
    type: 'button', style: { flexShrink: '0' }
  });
  openaiKeyToggle.textContent = 'Show';
  openaiKeyToggle.addEventListener('click', () => {
    const isPassword = openaiKeyInput.type === 'password';
    openaiKeyInput.type = isPassword ? 'text' : 'password';
    openaiKeyToggle.textContent = isPassword ? 'Hide' : 'Show';
  });
  openaiKeyRow.appendChild(openaiKeyInput);
  openaiKeyRow.appendChild(openaiKeyToggle);
  fieldRefs.openaiApiKey = openaiKeyInput;
  const openaiKeyField = createField('OpenAI API Key', openaiKeyRow, 'Your OpenAI key for unlimited voice usage');
  openaiKeyField.style.display = 'none'; // Hidden by default (xAI is default provider)
  section.appendChild(openaiKeyField);

  // Voice character selector
  const xaiVoiceSelect = createElement('select', {
    className: 'settings-select', 'aria-label': 'Voice character'
  });
  const xaiVoices = [
    { value: 'Ara', label: 'Ara (Female, Warm)' },
    { value: 'Rex', label: 'Rex (Male, Confident)' },
    { value: 'Sal', label: 'Sal (Neutral, Balanced)' },
    { value: 'Eve', label: 'Eve (Female, Energetic)' },
    { value: 'Leo', label: 'Leo (Male, Authoritative)' }
  ];
  for (const v of xaiVoices) {
    xaiVoiceSelect.appendChild(createElement('option', { value: v.value }, [v.label]));
  }
  xaiVoiceSelect.addEventListener('change', () => onNestedFieldChange('voice', 'xaiVoice', xaiVoiceSelect.value));
  fieldRefs.xaiVoice = xaiVoiceSelect;
  section.appendChild(createField('Voice Character', xaiVoiceSelect, 'Voice personality for conversations'));

  return section;
}

function buildIngestionSection() {
  const section = createSection('globe', 'Ingestion');

  // Enable toggle
  const enableRow = createElement('div', { className: 'settings-field-row' });
  const enableLabel = createElement('span', {
    style: { flex: '1', color: 'var(--text-primary)', fontSize: 'var(--font-size-sm)' }
  }, ['Enable Ingestion']);
  const enableToggle = createElement('button', {
    className: 'settings-toggle',
    'aria-label': 'Toggle ingestion',
    role: 'switch'
  });
  enableToggle.addEventListener('click', () => {
    const isActive = enableToggle.classList.toggle('active');
    enableToggle.setAttribute('aria-checked', String(isActive));
    onNestedFieldChange('ingestion', 'enabled', isActive);
  });
  fieldRefs.ingestionEnabled = enableToggle;
  enableRow.appendChild(enableLabel);
  enableRow.appendChild(enableToggle);
  section.appendChild(createField('Activation', enableRow));

  // Max concurrent
  const concurrentInput = createElement('input', {
    className: 'glass-input',
    type: 'number',
    min: '1',
    max: '10',
    step: '1',
    placeholder: '3',
    'aria-label': 'Max concurrent ingestion tasks',
    style: { width: '120px' }
  });
  concurrentInput.addEventListener('input', () =>
    onNestedFieldChange('ingestion', 'maxConcurrent', Number(concurrentInput.value))
  );
  fieldRefs.ingestionMaxConcurrent = concurrentInput;
  section.appendChild(createField('Max Concurrent', concurrentInput, 'Parallel ingestion tasks'));

  // Watch Folders
  const watchFoldersContainer = createElement('div', { className: 'watch-folders-container' });

  const folderListEl = createElement('div', {
    className: 'watch-folders-list',
    style: { display: 'flex', flexDirection: 'column', gap: 'var(--space-xs)', marginBottom: 'var(--space-sm)' }
  });
  watchFoldersContainer.appendChild(folderListEl);
  fieldRefs.watchFoldersList = folderListEl;

  function renderFolderList() {
    empty(folderListEl);
    const settings = store.getState().settings || {};
    const folders = settings.ingestion?.watchFolders || [];
    if (folders.length === 0) {
      folderListEl.appendChild(createElement('div', {
        style: { color: 'var(--text-tertiary)', fontSize: 'var(--font-size-sm)', padding: '2px 0' }
      }, ['No folders configured.']));
    }
    for (const folder of folders) {
      const row = createElement('div', {
        style: { display: 'flex', alignItems: 'center', gap: 'var(--space-xs)' }
      });
      const pathEl = createElement('span', {
        style: {
          flex: '1', fontSize: 'var(--font-size-xs)', color: 'var(--text-secondary)',
          overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap'
        }
      }, [folder]);
      const removeBtn = createElement('button', {
        className: 'glass-button glass-button-sm',
        'aria-label': `Remove folder ${folder}`,
        style: { color: 'var(--text-error, #f87171)', flexShrink: '0' }
      }, ['×']);
      removeBtn.addEventListener('click', () => {
        const s = store.getState().settings || {};
        const current = s.ingestion?.watchFolders || [];
        const updated = current.filter(f => f !== folder);
        onNestedFieldChange('ingestion', 'watchFolders', updated);
        renderFolderList();
      });
      row.appendChild(pathEl);
      row.appendChild(removeBtn);
      folderListEl.appendChild(row);
    }
  }
  fieldRefs.renderWatchFolderList = renderFolderList;
  renderFolderList();

  // Add Folder button / input
  function addFolder(path) {
    const trimmed = path.trim();
    if (!trimmed) return;
    const s = store.getState().settings || {};
    const current = s.ingestion?.watchFolders || [];
    if (current.includes(trimmed)) return;
    onNestedFieldChange('ingestion', 'watchFolders', [...current, trimmed]);
    renderFolderList();
  }

  const addRow = createElement('div', { style: { display: 'flex', gap: 'var(--space-xs)', alignItems: 'center' } });

  if (window.desktopBridge?.pickWorkspaceFolder) {
    // Electron: use native folder picker
    const addBtn = createElement('button', {
      className: 'glass-button glass-button-sm',
      style: { alignSelf: 'flex-start' }
    }, ['+ Add Folder']);
    addBtn.addEventListener('click', () => {
      window.desktopBridge.pickWorkspaceFolder().then((dir) => {
        if (dir) addFolder(dir);
      });
    });
    addRow.appendChild(addBtn);
  } else {
    // Browser: text input
    const folderInput = createElement('input', {
      className: 'glass-input',
      type: 'text',
      placeholder: '/absolute/path/to/folder',
      'aria-label': 'Folder path to watch',
      style: { flex: '1' }
    });
    const addBtn = createElement('button', {
      className: 'glass-button glass-button-sm glass-button-accent',
      style: { flexShrink: '0' }
    }, ['Add']);
    addBtn.addEventListener('click', () => {
      addFolder(folderInput.value);
      folderInput.value = '';
    });
    folderInput.addEventListener('keydown', (e) => {
      if (e.key === 'Enter') { addFolder(folderInput.value); folderInput.value = ''; }
    });
    addRow.appendChild(folderInput);
    addRow.appendChild(addBtn);
  }

  watchFoldersContainer.appendChild(addRow);
  section.appendChild(createField('Watch Folders', watchFoldersContainer,
    'New files dropped in these folders are automatically queued for ingestion (.txt, .md, .html, .pdf, .json, .csv)'));

  return section;
}

function buildCognitiveSection() {
  const section = createSection('focus', 'Cognitive');

  // Planner enable
  const plannerRow = createElement('div', { className: 'settings-field-row' });
  const plannerLabel = createElement('span', {
    style: { flex: '1', color: 'var(--text-primary)', fontSize: 'var(--font-size-sm)' }
  }, ['Enable Planner']);
  const plannerToggle = createElement('button', {
    className: 'settings-toggle',
    'aria-label': 'Toggle planner',
    role: 'switch'
  });
  plannerToggle.addEventListener('click', () => {
    const isActive = plannerToggle.classList.toggle('active');
    plannerToggle.setAttribute('aria-checked', String(isActive));
    onNestedFieldChange('cognitive', 'plannerEnabled', isActive);
  });
  fieldRefs.plannerEnabled = plannerToggle;
  plannerRow.appendChild(plannerLabel);
  plannerRow.appendChild(plannerToggle);
  section.appendChild(createField('Planner', plannerRow));

  // Reflector enable
  const reflectorRow = createElement('div', { className: 'settings-field-row' });
  const reflectorLabel = createElement('span', {
    style: { flex: '1', color: 'var(--text-primary)', fontSize: 'var(--font-size-sm)' }
  }, ['Enable Reflector']);
  const reflectorToggle = createElement('button', {
    className: 'settings-toggle',
    'aria-label': 'Toggle reflector',
    role: 'switch'
  });
  reflectorToggle.addEventListener('click', () => {
    const isActive = reflectorToggle.classList.toggle('active');
    reflectorToggle.setAttribute('aria-checked', String(isActive));
    onNestedFieldChange('cognitive', 'reflectorEnabled', isActive);
  });
  fieldRefs.reflectorEnabled = reflectorToggle;
  reflectorRow.appendChild(reflectorLabel);
  reflectorRow.appendChild(reflectorToggle);
  section.appendChild(createField('Reflector', reflectorRow));

  // Reflector interval
  const intervalInput = createElement('input', {
    className: 'glass-input',
    type: 'number',
    min: '5',
    max: '1440',
    step: '5',
    placeholder: '60',
    'aria-label': 'Reflector interval in minutes',
    style: { width: '120px' }
  });
  intervalInput.addEventListener('input', () =>
    onNestedFieldChange('cognitive', 'reflectorInterval', Number(intervalInput.value))
  );
  fieldRefs.reflectorInterval = intervalInput;
  section.appendChild(createField('Reflector Interval', createFieldRow([
    intervalInput,
    createElement('span', {
      style: { color: 'var(--text-tertiary)', fontSize: 'var(--font-size-sm)' }
    }, ['minutes'])
  ]), 'How often the reflector runs'));

  // Thinking depth
  const depthRow = createElement('div', { className: 'settings-field-row' });
  const depthRange = createElement('input', {
    className: 'settings-range',
    type: 'range',
    min: '1',
    max: '5',
    step: '1',
    value: '3',
    'aria-label': 'Thinking depth'
  });
  const depthValue = createElement('span', { className: 'settings-range-value' }, ['3']);
  depthRange.addEventListener('input', () => {
    depthValue.textContent = depthRange.value;
    onNestedFieldChange('cognitive', 'thinkerDepth', Number(depthRange.value));
  });
  fieldRefs.thinkerDepth = depthRange;
  fieldRefs.thinkerDepthDisplay = depthValue;
  depthRow.appendChild(depthRange);
  depthRow.appendChild(depthValue);
  section.appendChild(createField('Thinking Depth', depthRow, 'Depth of chain-of-thought reasoning (1-5)'));

  return section;
}

function buildSchedulesSection() {
  const section = createSection('clock', 'Scheduled Tasks');
  const listEl = createElement('div', { className: 'schedules-list' });

  // State
  let schedules = [];
  let skillNames = [];

  async function refresh() {
    try {
      [schedules, skillNames] = await Promise.all([
        api.getSchedules(),
        api.getSkillsPalette().then(p => p.map(s => s.name)).catch(() => [])
      ]);
    } catch {
      schedules = [];
    }
    renderList();
  }

  function renderList() {
    empty(listEl);
    if (!schedules.length) {
      listEl.appendChild(createElement('div', {
        style: { color: 'var(--text-tertiary)', fontSize: 'var(--font-size-sm)', padding: '4px 0' }
      }, ['No scheduled tasks yet.']));
    }
    for (const s of schedules) {
      const row = createElement('div', {
        className: 'schedule-item',
        style: {
          display: 'flex', alignItems: 'center', gap: 'var(--space-sm)',
          padding: '6px 0', borderBottom: '1px solid var(--border-subtle)'
        }
      });

      const info = createElement('div', { style: { flex: '1', minWidth: '0' } }, [
        createElement('div', {
          style: { fontWeight: '500', fontSize: 'var(--font-size-sm)', color: 'var(--text-primary)' }
        }, [s.name]),
        createElement('div', {
          style: { fontSize: 'var(--font-size-xs)', color: 'var(--text-tertiary)' }
        }, [`${s.skill} · ${s.interval}`])
      ]);

      const toggle = createElement('button', {
        className: `settings-toggle${s.enabled ? ' active' : ''}`,
        'aria-label': 'Toggle schedule',
        role: 'switch',
        'aria-checked': String(!!s.enabled)
      });
      toggle.addEventListener('click', async () => {
        const isActive = toggle.classList.toggle('active');
        toggle.setAttribute('aria-checked', String(isActive));
        try {
          await api.updateSchedule(s.id, { enabled: isActive });
          s.enabled = isActive;
        } catch (err) {
          console.error('[schedules] update failed:', err);
        }
      });

      const delBtn = createElement('button', {
        className: 'glass-button glass-button-sm',
        'aria-label': 'Delete schedule',
        style: { color: 'var(--text-error, #f87171)', flexShrink: '0' }
      }, ['×']);
      delBtn.addEventListener('click', async () => {
        try {
          await api.deleteSchedule(s.id);
          await refresh();
        } catch (err) {
          console.error('[schedules] delete failed:', err);
        }
      });

      row.appendChild(info);
      row.appendChild(toggle);
      row.appendChild(delBtn);
      listEl.appendChild(row);
    }
  }

  // Inline add form
  const formEl = createElement('div', {
    className: 'schedule-add-form',
    style: { display: 'none', flexDirection: 'column', gap: 'var(--space-sm)', marginTop: 'var(--space-sm)' }
  });

  const nameInput = createElement('input', {
    className: 'glass-input',
    type: 'text',
    placeholder: 'Task name',
    'aria-label': 'Schedule name'
  });

  const skillSelect = createElement('select', {
    className: 'glass-input',
    'aria-label': 'Skill to run'
  });

  const intervalSelect = createElement('select', {
    className: 'glass-input',
    'aria-label': 'Run interval'
  });
  [
    { value: 'hourly', label: 'Hourly' },
    { value: 'daily', label: 'Daily' },
    { value: 'weekly', label: 'Weekly' },
    { value: '30', label: 'Every 30 min' },
    { value: '60', label: 'Every hour' },
    { value: '120', label: 'Every 2 hours' }
  ].forEach(({ value, label }) => {
    const opt = createElement('option', { value }, [label]);
    intervalSelect.appendChild(opt);
  });

  const formBtns = createElement('div', { style: { display: 'flex', gap: 'var(--space-xs)' } });
  const saveBtn = createElement('button', { className: 'glass-button glass-button-accent glass-button-sm' }, ['Save']);
  const cancelBtn = createElement('button', { className: 'glass-button glass-button-sm' }, ['Cancel']);
  formBtns.appendChild(saveBtn);
  formBtns.appendChild(cancelBtn);

  formEl.appendChild(nameInput);
  formEl.appendChild(skillSelect);
  formEl.appendChild(intervalSelect);
  formEl.appendChild(formBtns);

  const addBtn = createElement('button', {
    className: 'glass-button glass-button-sm',
    style: { marginTop: 'var(--space-sm)', alignSelf: 'flex-start' }
  }, ['+ Add Schedule']);

  addBtn.addEventListener('click', async () => {
    // Populate skill dropdown lazily
    empty(skillSelect);
    const names = skillNames.length ? skillNames : (await api.getSkillsPalette().catch(() => [])).map(s => s.name);
    skillNames = names;
    names.forEach(n => {
      skillSelect.appendChild(createElement('option', { value: n }, [n]));
    });
    formEl.style.display = 'flex';
    addBtn.style.display = 'none';
    nameInput.focus();
  });

  cancelBtn.addEventListener('click', () => {
    formEl.style.display = 'none';
    addBtn.style.display = '';
    nameInput.value = '';
  });

  saveBtn.addEventListener('click', async () => {
    const name = nameInput.value.trim();
    const skill = skillSelect.value;
    const interval = intervalSelect.value;
    if (!name || !skill) return;
    try {
      await api.createSchedule({ name, skill, interval });
      nameInput.value = '';
      formEl.style.display = 'none';
      addBtn.style.display = '';
      await refresh();
    } catch (err) {
      console.error('[schedules] create failed:', err);
    }
  });

  section.appendChild(listEl);
  section.appendChild(formEl);
  section.appendChild(addBtn);

  // Load on mount
  refresh();

  return section;
}

function buildAdvancedSection() {
  const section = createSection('configure', 'Advanced');

  // Workspace root (readonly)
  const wsRow = createElement('div', { className: 'settings-field-row' });
  const wsInput = createElement('input', {
    className: 'glass-input',
    type: 'text',
    readonly: 'true',
    'aria-label': 'Workspace root path',
    style: { flex: '1', opacity: '0.7' }
  });
  fieldRefs.workspaceRoot = wsInput;

  // Show change button only in desktop (Electron) context
  const wsChangeBtn = createElement('button', {
    className: 'glass-button glass-button-sm',
    style: { display: 'none' }
  }, ['Change']);
  wsChangeBtn.addEventListener('click', () => {
    if (window.desktopBridge?.pickWorkspaceFolder) {
      window.desktopBridge.pickWorkspaceFolder().then((dir) => {
        if (dir) {
          wsInput.value = dir;
          onFieldChange('workspaceRoot', dir);
        }
      });
    }
  });
  // Show button if running in Electron
  if (window.desktopBridge) {
    wsChangeBtn.style.display = '';
  }
  fieldRefs.wsChangeBtn = wsChangeBtn;

  wsRow.appendChild(wsInput);
  wsRow.appendChild(wsChangeBtn);
  section.appendChild(createField('Workspace Root', wsRow, 'Directory where agent output files are stored'));

  // Auth token (collapsed by default — most users don't need this)
  const tokenDetails = createElement('details', {
    style: { marginTop: 'var(--space-sm)' }
  });
  const tokenSummary = createElement('summary', {
    style: {
      cursor: 'pointer', fontSize: 'var(--font-size-sm)', color: 'var(--text-secondary)',
      userSelect: 'none', padding: 'var(--space-xs) 0'
    }
  }, ['Show API Auth Token']);
  tokenDetails.appendChild(tokenSummary);
  const tokenField = createElement('div', { className: 'settings-token-field', style: { marginTop: 'var(--space-xs)' } });
  const tokenText = createElement('span', {}, ['****']);
  fieldRefs.authToken = tokenText;
  const tokenCopyBtn = createElement('button', {
    className: 'glass-button glass-button-sm',
    style: { marginLeft: 'auto', flexShrink: '0' },
    'aria-label': 'Copy auth token'
  }, [
    icon('copy', { size: 14 })
  ]);
  tokenCopyBtn.addEventListener('click', () => {
    const settings = store.getState().settings;
    const token = settings.authToken || '';
    if (token && navigator.clipboard) {
      navigator.clipboard.writeText(token).then(() => {
        tokenCopyBtn.textContent = '';
        tokenCopyBtn.appendChild(icon('check', { size: 14 }));
        setTimeout(() => {
          tokenCopyBtn.textContent = '';
          tokenCopyBtn.appendChild(icon('copy', { size: 14 }));
        }, 2000);
      });
    }
  });
  tokenField.appendChild(tokenText);
  tokenField.appendChild(tokenCopyBtn);
  tokenDetails.appendChild(tokenField);
  section.appendChild(tokenDetails);

  // Version display
  const versionRow = createElement('div', { className: 'settings-field-row' });
  versionRow.appendChild(createElement('span', {
    style: { color: 'var(--text-primary)', fontSize: 'var(--font-size-sm)' }
  }, [`v${currentVersion}`]));
  versionRow.appendChild(createElement('span', { className: 'settings-badge' }, ['Current']));
  section.appendChild(createField('Version', versionRow));

  return section;
}

// ──────────────────────────────────────
// Helper: create section container
// ──────────────────────────────────────

function createSection(iconName, title) {
  const section = createElement('div', { className: 'settings-section' });
  const titleEl = createElement('div', { className: 'settings-section-title' }, [
    icon(iconName, { size: 20 }),
    title
  ]);
  section.appendChild(titleEl);
  return section;
}

// ──────────────────────────────────────
// Helper: create field wrapper
// ──────────────────────────────────────

function createField(label, content, hint) {
  const field = createElement('div', { className: 'settings-field' });
  field.appendChild(createElement('label', { className: 'settings-field-label' }, [label]));

  if (typeof content === 'string') {
    field.appendChild(document.createTextNode(content));
  } else if (content instanceof Node) {
    field.appendChild(content);
  }

  if (hint) {
    field.appendChild(createElement('span', { className: 'settings-field-hint' }, [hint]));
  }

  return field;
}

// ──────────────────────────────────────
// Helper: create inline field row
// ──────────────────────────────────────

function createFieldRow(children) {
  return createElement('div', { className: 'settings-field-row' }, children);
}

// ──────────────────────────────────────
// Populate fields from store
// ──────────────────────────────────────

function populateFromStore() {
  const settings = store.getState().settings || {};
  const theme = store.getState().ui.theme || 'dark';

  // General
  if (fieldRefs.agentName) fieldRefs.agentName.value = settings.agentName || '';
  if (fieldRefs.loopMinutes) fieldRefs.loopMinutes.value = settings.loopMinutes ?? '';
  if (fieldRefs.dailyBudget) fieldRefs.dailyBudget.value = settings.dailyBudget ?? '';

  // Autonomy
  const autonomy = settings.autonomy || {};
  if (fieldRefs.autonomyEnabled) {
    fieldRefs.autonomyEnabled.classList.toggle('active', autonomy.enabled !== false);
    fieldRefs.autonomyEnabled.setAttribute('aria-checked', String(autonomy.enabled !== false));
  }
  if (fieldRefs.autonomyIntervalMinutes) {
    fieldRefs.autonomyIntervalMinutes.value = autonomy.intervalMinutes ?? 30;
  }

  // LLM
  if (fieldRefs.cli) fieldRefs.cli.value = settings.cli || 'claude';
  const models = settings.models || {};
  if (fieldRefs.modelOverride_fast) fieldRefs.modelOverride_fast.value = models.fast || '';
  if (fieldRefs.modelOverride_balanced) fieldRefs.modelOverride_balanced.value = models.balanced || '';
  if (fieldRefs.modelOverride_powerful) fieldRefs.modelOverride_powerful.value = models.powerful || '';

  // Gergy / Agentic config
  const agentic = settings.agentic || {};
  if (fieldRefs.agenticProvider) fieldRefs.agenticProvider.value = agentic.provider || 'anthropic';
  if (fieldRefs.agenticApiKey) fieldRefs.agenticApiKey.value = agentic.apiKey || '';
  if (fieldRefs.agenticBaseUrl) fieldRefs.agenticBaseUrl.value = agentic.baseUrl || '';
  const gergySection = container?.querySelector('.settings-gergy-config');
  if (gergySection) gergySection.style.display = (settings.cli === 'gergy') ? '' : 'none';

  // Appearance
  if (fieldRefs.theme) {
    fieldRefs.theme.classList.toggle('active', theme === 'dark');
    fieldRefs.theme.setAttribute('aria-checked', String(theme === 'dark'));
  }
  if (fieldRefs.fontSize) {
    const currentSize = document.documentElement.getAttribute('data-font-size') || 'medium';
    for (const [size, btn] of Object.entries(fieldRefs.fontSize)) {
      btn.classList.toggle('active', size === currentSize);
    }
  }

  // Accent color — highlight the selected preset button
  if (fieldRefs.accentColor?.buttons) {
    const savedAccent = settings.accentColor || 'Indigo';
    const presets = fieldRefs.accentColor.presets;
    fieldRefs.accentColor.buttons.forEach((btn, i) => {
      btn.style.borderColor = presets[i].name === savedAccent ? 'var(--text-primary)' : 'transparent';
    });
  }

  // Voice
  const voice = settings.voice || {};
  if (fieldRefs.voiceEnabled) {
    fieldRefs.voiceEnabled.classList.toggle('active', !!voice.enabled);
    fieldRefs.voiceEnabled.setAttribute('aria-checked', String(!!voice.enabled));
  }
  if (fieldRefs.wakeWordModel) fieldRefs.wakeWordModel.value = voice.wakeWordModel || '';
  if (fieldRefs.detectionThreshold) {
    const thresh = voice.detectionThreshold ?? 0.5;
    fieldRefs.detectionThreshold.value = thresh;
    if (fieldRefs.detectionThresholdDisplay) {
      fieldRefs.detectionThresholdDisplay.textContent = Number(thresh).toFixed(2);
    }
  }
  if (fieldRefs.listenHotkey) fieldRefs.listenHotkey.value = voice.listenHotkey || '';
  if (fieldRefs.voiceProvider) fieldRefs.voiceProvider.value = voice.provider || 'xai';
  if (fieldRefs.xaiApiKey) fieldRefs.xaiApiKey.value = voice.xaiApiKey || '';
  if (fieldRefs.openaiApiKey) fieldRefs.openaiApiKey.value = voice.openaiApiKey || '';
  if (fieldRefs.xaiVoice) fieldRefs.xaiVoice.value = voice.xaiVoice || 'Sal';

  // Show/hide voice provider key fields based on selected provider
  const voiceProvider = voice.provider || 'xai';
  const xaiKeyFieldEl = fieldRefs.xaiApiKey?.closest?.('.settings-field');
  const openaiKeyFieldEl = fieldRefs.openaiApiKey?.closest?.('.settings-field');
  if (xaiKeyFieldEl) xaiKeyFieldEl.style.display = voiceProvider === 'xai' ? '' : 'none';
  if (openaiKeyFieldEl) openaiKeyFieldEl.style.display = voiceProvider === 'openai' ? '' : 'none';

  // Connection status
  if (fieldRefs.connectionStatus) {
    const worker = settings.worker || {};
    if (agentic.apiKey) {
      const providerName = (agentic.provider || 'anthropic').charAt(0).toUpperCase() + (agentic.provider || 'anthropic').slice(1);
      fieldRefs.connectionStatus.textContent = `Connected via: Your ${providerName} API key`;
      fieldRefs.connectionStatus.style.borderColor = 'var(--accent-primary)';
    } else if (worker.url) {
      fieldRefs.connectionStatus.textContent = `Connected via: Hosted AI proxy (${worker.dailyLimit || 100} requests/day)`;
      fieldRefs.connectionStatus.style.borderColor = 'var(--text-tertiary)';
      // Fetch actual usage asynchronously
      fetchWorkerUsage(worker.url, fieldRefs.connectionStatus);
    } else {
      fieldRefs.connectionStatus.textContent = 'Not connected — configure an API key or enable hosted proxy';
      fieldRefs.connectionStatus.style.borderColor = 'var(--error)';
    }
  }

  // Ingestion
  const ingestion = settings.ingestion || {};
  if (fieldRefs.ingestionEnabled) {
    fieldRefs.ingestionEnabled.classList.toggle('active', !!ingestion.enabled);
    fieldRefs.ingestionEnabled.setAttribute('aria-checked', String(!!ingestion.enabled));
  }
  if (fieldRefs.ingestionMaxConcurrent) {
    fieldRefs.ingestionMaxConcurrent.value = ingestion.maxConcurrent ?? '';
  }
  if (fieldRefs.renderWatchFolderList) {
    fieldRefs.renderWatchFolderList();
  }

  // Cognitive
  const cognitive = settings.cognitive || {};
  if (fieldRefs.plannerEnabled) {
    fieldRefs.plannerEnabled.classList.toggle('active', !!cognitive.plannerEnabled);
    fieldRefs.plannerEnabled.setAttribute('aria-checked', String(!!cognitive.plannerEnabled));
  }
  if (fieldRefs.reflectorEnabled) {
    fieldRefs.reflectorEnabled.classList.toggle('active', !!cognitive.reflectorEnabled);
    fieldRefs.reflectorEnabled.setAttribute('aria-checked', String(!!cognitive.reflectorEnabled));
  }
  if (fieldRefs.reflectorInterval) {
    fieldRefs.reflectorInterval.value = cognitive.reflectorInterval ?? '';
  }
  if (fieldRefs.thinkerDepth) {
    const depth = cognitive.thinkerDepth ?? 3;
    fieldRefs.thinkerDepth.value = depth;
    if (fieldRefs.thinkerDepthDisplay) {
      fieldRefs.thinkerDepthDisplay.textContent = String(depth);
    }
  }

  // Notifications
  const notifications = settings.notifications || {};
  if (fieldRefs.notificationsEnabled) {
    fieldRefs.notificationsEnabled.classList.toggle('active', notifications.enabled !== false);
    fieldRefs.notificationsEnabled.setAttribute('aria-checked', String(notifications.enabled !== false));
  }

  // Advanced
  if (fieldRefs.workspaceRoot) {
    fieldRefs.workspaceRoot.value = settings.workspaceRoot || './workspace';
  }
  if (fieldRefs.authToken) {
    const token = settings.authToken || '';
    fieldRefs.authToken.textContent = token ? maskToken(token) : '(none)';
  }

  dirty = false;
}

// ──────────────────────────────────────
// Worker usage check
// ──────────────────────────────────────

async function fetchWorkerUsage(workerUrl, statusEl) {
  try {
    const res = await fetch(`${workerUrl}/api/v1/usage`);
    if (!res.ok) return;
    const data = await res.json();
    const remaining = data.llm?.remaining ?? '?';
    const limit = data.llm?.limit ?? 100;
    statusEl.textContent = `Connected via: Hosted AI proxy (${remaining}/${limit} requests remaining today)`;
  } catch {
    // Worker may not be deployed yet — leave default text
  }
}

// Field change handlers
// ──────────────────────────────────────

function onFieldChange(key, value) {
  dirty = true;
  store.dispatch('SET_SETTINGS', { [key]: value });
}

function onNestedFieldChange(namespace, key, value) {
  dirty = true;
  const settings = store.getState().settings || {};
  const nested = { ...(settings[namespace] || {}), [key]: value };
  store.dispatch('SET_SETTINGS', { [namespace]: nested });
}

// ──────────────────────────────────────
// Save to server
// ──────────────────────────────────────

async function saveSettings() {
  const settings = store.getState().settings || {};

  // Build the config payload (flatten model overrides into models object)
  const payload = { ...settings };

  // Merge model overrides back into a models map
  const models = { ...(settings.models || {}) };
  if (payload.modelOverride_fast !== undefined) {
    if (payload.modelOverride_fast) models.fast = payload.modelOverride_fast;
    delete payload.modelOverride_fast;
  }
  if (payload.modelOverride_balanced !== undefined) {
    if (payload.modelOverride_balanced) models.balanced = payload.modelOverride_balanced;
    delete payload.modelOverride_balanced;
  }
  if (payload.modelOverride_powerful !== undefined) {
    if (payload.modelOverride_powerful) models.powerful = payload.modelOverride_powerful;
    delete payload.modelOverride_powerful;
  }
  payload.models = models;

  // Remove readonly fields
  delete payload.authToken;

  // Also remove fontSize from config payload (it's a UI-only setting)
  const fontSize = payload.fontSize;
  delete payload.fontSize;

  try {
    await api.updateConfig(payload);
    dirty = false;

    // Persist font size preference in localStorage
    if (fontSize) {
      localStorage.setItem('aido-font-size', fontSize);
    }

    console.log('[settings] Config saved successfully');
  } catch (err) {
    console.error('[settings] Save failed:', err);
  }
}

// ──────────────────────────────────────
// Utilities
// ──────────────────────────────────────

function maskToken(token) {
  if (token.length <= 8) return '****';
  return token.slice(0, 4) + '****' + token.slice(-4);
}
