/**
 * 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';

const VERSION = '4.0.0';

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

// ──────────────────────────────────────
// 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 = await api.getConfig();
    store.dispatch('SET_SETTINGS', config);
  } catch (err) {
    console.error('[settings] Failed to load config:', err);
  }
  buildDOM();
  populateFromStore();
}

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

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);

  // Sections
  panel.appendChild(buildGeneralSection());
  panel.appendChild(buildLLMSection());
  panel.appendChild(buildAppearanceSection());
  panel.appendChild(buildVoiceSection());
  panel.appendChild(buildIngestionSection());
  panel.appendChild(buildCognitiveSection());
  panel.appendChild(buildAdvancedSection());

  // Version
  const versionEl = createElement('div', { className: 'settings-version' }, [
    `AI-Do v${VERSION}`
  ]);
  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);
}

// ──────────────────────────────────────
// 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('name', nameInput.value));
  fieldRefs.name = nameInput;
  section.appendChild(createField('Name', nameInput, 'The display name of your agent'));

  // 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'));

  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'];
  for (const a of adapters) {
    const opt = createElement('option', { value: a }, [a.charAt(0).toUpperCase() + a.slice(1)]);
    adapterSelect.appendChild(opt);
  }
  adapterSelect.addEventListener('change', () => onFieldChange('cli', adapterSelect.value));
  fieldRefs.cli = adapterSelect;
  section.appendChild(createField('Adapter', adapterSelect, 'Which LLM backend to use'));

  // Model overrides title
  section.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;
    section.appendChild(createField(tier.charAt(0).toUpperCase() + tier.slice(1), input));
  }

  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 swatch
  const colorRow = createElement('div', { className: 'settings-field-row' });
  const swatch = createElement('div', {
    className: 'settings-color-swatch',
    style: { background: 'var(--accent-gradient)' }
  });
  const colorLabel = createElement('span', {
    className: 'settings-badge'
  }, ['Indigo']);
  colorRow.appendChild(swatch);
  colorRow.appendChild(colorLabel);
  fieldRefs.accentColor = { swatch, label: colorLabel };
  section.appendChild(createField('Accent Color', colorRow, 'Current accent color'));

  return section;
}

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

  // 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 Voice']);
  const enableToggle = createElement('button', {
    className: 'settings-toggle',
    'aria-label': 'Toggle voice',
    role: 'switch'
  });
  enableToggle.addEventListener('click', () => {
    const isActive = enableToggle.classList.toggle('active');
    enableToggle.setAttribute('aria-checked', String(isActive));
    onNestedFieldChange('voice', 'enabled', isActive);
  });
  fieldRefs.voiceEnabled = enableToggle;
  enableRow.appendChild(enableLabel);
  enableRow.appendChild(enableToggle);
  section.appendChild(createField('Activation', enableRow));

  // Wake word model
  const wakeInput = createElement('input', {
    className: 'glass-input',
    type: 'text',
    placeholder: 'hey_jarvis',
    'aria-label': 'Wake word model name'
  });
  wakeInput.addEventListener('input', () => onNestedFieldChange('voice', 'wakeWordModel', wakeInput.value));
  fieldRefs.wakeWordModel = wakeInput;
  section.appendChild(createField('Wake Word Model', wakeInput, 'ONNX model name in data/wake-word-models/'));

  // Detection threshold
  const thresholdRow = createElement('div', { className: 'settings-field-row' });
  const thresholdRange = createElement('input', {
    className: 'settings-range',
    type: 'range',
    min: '0',
    max: '1',
    step: '0.05',
    value: '0.5',
    'aria-label': 'Detection threshold'
  });
  const thresholdValue = createElement('span', { className: 'settings-range-value' }, ['0.50']);
  thresholdRange.addEventListener('input', () => {
    const val = Number(thresholdRange.value);
    thresholdValue.textContent = val.toFixed(2);
    onNestedFieldChange('voice', 'detectionThreshold', val);
  });
  fieldRefs.detectionThreshold = thresholdRange;
  fieldRefs.detectionThresholdDisplay = thresholdValue;
  thresholdRow.appendChild(thresholdRange);
  thresholdRow.appendChild(thresholdValue);
  section.appendChild(createField('Detection Threshold', thresholdRow));

  // Listen hotkey
  const hotkeyInput = createElement('input', {
    className: 'glass-input',
    type: 'text',
    placeholder: 'Cmd+Shift+Space',
    'aria-label': 'Listen hotkey',
    style: { width: '200px' }
  });
  hotkeyInput.addEventListener('input', () => onNestedFieldChange('voice', 'listenHotkey', hotkeyInput.value));
  fieldRefs.listenHotkey = hotkeyInput;
  section.appendChild(createField('Listen Hotkey', hotkeyInput, 'Keyboard shortcut for instant listen'));

  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'));

  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', 'thinkingDepth', Number(depthRange.value));
  });
  fieldRefs.thinkingDepth = depthRange;
  fieldRefs.thinkingDepthDisplay = depthValue;
  depthRow.appendChild(depthRange);
  depthRow.appendChild(depthValue);
  section.appendChild(createField('Thinking Depth', depthRow, 'Depth of chain-of-thought reasoning (1-5)'));

  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.electronAPI?.selectDirectory) {
      window.electronAPI.selectDirectory().then((dir) => {
        if (dir) {
          wsInput.value = dir;
          onFieldChange('workspaceRoot', dir);
        }
      });
    }
  });
  // Show button if running in Electron
  if (window.electronAPI) {
    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 (masked, readonly)
  const tokenField = createElement('div', { className: 'settings-token-field' });
  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);
  section.appendChild(createField('Auth Token', tokenField, 'Bearer token for API authentication'));

  // 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${VERSION}`]));
  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.name) fieldRefs.name.value = settings.name || '';
  if (fieldRefs.loopMinutes) fieldRefs.loopMinutes.value = settings.loopMinutes ?? '';
  if (fieldRefs.dailyBudget) fieldRefs.dailyBudget.value = settings.dailyBudget ?? '';

  // 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 || '';

  // 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);
    }
  }

  // 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 || '';

  // 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 ?? '';
  }

  // 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.thinkingDepth) {
    const depth = cognitive.thinkingDepth ?? 3;
    fieldRefs.thinkingDepth.value = depth;
    if (fieldRefs.thinkingDepthDisplay) {
      fieldRefs.thinkingDepthDisplay.textContent = String(depth);
    }
  }

  // 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;
}

// ──────────────────────────────────────
// 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);
}
