// settings.js — Briefing settings, news topics, credentials, routing
// Extracted from dashboard.html (lines 7089-7572)

// ── Daily Briefing settings ────────────────────────────────────────
async function loadBriefingSettings() {
    try {
        const res = await apiFetch(API + '/api/settings/briefing');
        const data = await res.json();
        const tog = document.getElementById('toggle-briefing');
        const row = document.getElementById('briefing-time-row');
        const inp = document.getElementById('briefing-time-input');
        const status = document.getElementById('briefing-status');
        if (!tog) return;
        if (data.enabled) {
            tog.classList.add('on');
            row.style.display = 'block';
        } else {
            tog.classList.remove('on');
            row.style.display = 'none';
        }
        inp.value = data.time || '08:00';
        status.textContent = data.enabled ? 'Briefing active at ' + (data.time || '08:00') : 'Briefing off';
    } catch (_) {}
}

async function toggleBriefing() {
    const tog = document.getElementById('toggle-briefing');
    const row = document.getElementById('briefing-time-row');
    const inp = document.getElementById('briefing-time-input');
    const willEnable = !tog.classList.contains('on');
    tog.classList.toggle('on', willEnable);
    row.style.display = willEnable ? 'block' : 'none';
    try {
        await apiFetch(API + '/api/settings/briefing', {
            method: 'POST',
            headers: {'Content-Type': 'application/json'},
            body: JSON.stringify({enabled: willEnable, time: inp.value || '08:00'})
        });
        await loadBriefingSettings();
    } catch (_) {}
}

async function saveBriefingTime() {
    const tog = document.getElementById('toggle-briefing');
    const inp = document.getElementById('briefing-time-input');
    const status = document.getElementById('briefing-status');
    const enabled = tog.classList.contains('on');
    try {
        const res = await apiFetch(API + '/api/settings/briefing', {
            method: 'POST',
            headers: {'Content-Type': 'application/json'},
            body: JSON.stringify({enabled, time: inp.value || '08:00'})
        });
        const data = await res.json();
        if (data.error) { status.textContent = data.error; return; }
        status.textContent = data.message || 'Saved';
        setTimeout(() => loadBriefingSettings(), 1200);
    } catch (_) {}
}

// ── News Topics settings ────────────────────────────────────────────
let _newsTopics = [];

async function loadNewsTopics() {
    try {
        const res = await apiFetch(API + '/api/settings/news-topics');
        const data = await res.json();
        _newsTopics = data.topics || [];
        renderNewsTopics();
        const addRow = document.getElementById('news-add-row');
        if (addRow) addRow.style.display = _newsTopics.length >= 5 ? 'none' : 'flex';
    } catch (_) {}
}

function renderNewsTopics() {
    const el = document.getElementById('news-topics-list');
    if (!el) return;
    if (!_newsTopics.length) {
        el.innerHTML = '<span style="font-size:0.8rem;color:var(--text-dim);">No topics yet</span>';
        return;
    }
    el.innerHTML = _newsTopics.map((t, i) =>
        '<span style="display:inline-flex;align-items:center;gap:4px;margin:3px 4px 3px 0;padding:3px 10px;background:var(--bg-input);border:1px solid var(--border);border-radius:20px;font-size:0.8rem;">'
        + escapeHtml(t)
        + '<button onclick="removeNewsTopic(' + i + ')" style="background:none;border:none;cursor:pointer;color:var(--text-dim);font-size:0.85rem;padding:0 0 0 4px;line-height:1;" title="Remove">&times;</button>'
        + '</span>'
    ).join('');
}

async function addNewsTopic() {
    if (_newsTopics.length >= 5) return;
    const inp = document.getElementById('news-topic-input');
    const msg = document.getElementById('news-topics-msg');
    const topic = inp.value.trim().toLowerCase();
    if (!topic) return;
    if (_newsTopics.includes(topic)) {
        msg.textContent = 'Already tracking "' + topic + '"';
        return;
    }
    _newsTopics.push(topic);
    inp.value = '';
    msg.textContent = '';
    await saveNewsTopics();
}

async function removeNewsTopic(idx) {
    _newsTopics.splice(idx, 1);
    await saveNewsTopics();
}

async function saveNewsTopics() {
    try {
        const res = await apiFetch(API + '/api/settings/news-topics', {
            method: 'POST',
            headers: {'Content-Type': 'application/json'},
            body: JSON.stringify({topics: _newsTopics})
        });
        const data = await res.json();
        if (data.topics) _newsTopics = data.topics;
        renderNewsTopics();
        const addRow = document.getElementById('news-add-row');
        if (addRow) addRow.style.display = _newsTopics.length >= 5 ? 'none' : 'flex';
    } catch (_) {}
}

// ── Settings Tab Switching + Credential Cards ─────────────────
let _credData = [];
let _credFilter = 'all';

function switchSettingsTab(tab) {
    const tabs = ['general', 'credentials', 'activity'];
    document.querySelectorAll('.set-tab').forEach((t, i) => {
        t.classList.toggle('active', tabs[i] === tab);
    });
    tabs.forEach(t => {
        const el = document.getElementById('set-' + t + '-tab');
        if (el) el.style.display = t === tab ? '' : 'none';
    });
    if (tab === 'credentials') loadCredentialCards();
    if (tab === 'activity') loadCredentialAudit();
}

async function loadCredentialAudit() {
    const list = document.getElementById('cred-audit-list');
    list.innerHTML = '<div class="loading"><div class="spinner"></div></div>';
    try {
        const res = await apiFetch(API + '/api/credentials/audit?limit=50');
        const data = await res.json();
        const events = data.events || [];
        if (events.length === 0) {
            list.innerHTML = '<div class="cred-empty-lg">No credential events recorded yet.</div>';
            return;
        }
        const typeIcons = {
            validated: '<i class="fas fa-check-circle cred-audit-icon-validated"></i>',
            refreshed: '<i class="fas fa-sync-alt cred-audit-icon-refreshed"></i>',
            updated: '<i class="fas fa-pen cred-audit-icon-updated"></i>',
            failed: '<i class="fas fa-times-circle cred-audit-icon-failed"></i>',
            accessed: '<i class="fas fa-eye cred-audit-icon-accessed"></i>',
            invalidated: '<i class="fas fa-ban cred-audit-icon-invalidated"></i>',
            created: '<i class="fas fa-plus-circle cred-audit-icon-created"></i>',
            deleted: '<i class="fas fa-trash cred-audit-icon-deleted"></i>',
            preflight_blocked: '<i class="fas fa-shield-alt cred-audit-icon-preflight_blocked"></i>',
            retry_refresh: '<i class="fas fa-redo cred-audit-icon-retry_refresh"></i>',
        };
        list.innerHTML = events.map(ev => {
            const icon = typeIcons[ev.event_type] || '<i class="fas fa-circle cred-audit-icon-accessed"></i>';
            const ts = ev.timestamp ? formatDate(ev.timestamp, 'datetime') : '';
            const svc = (ev.service_key || '').replace(/_/g, ' ').replace(/\b\w/g, c => c.toUpperCase());
            const typ = (ev.event_type || '').replace(/_/g, ' ');
            const detail = ev.details ? '<span class="cred-audit-detail">' + ev.details.substring(0, 80) + '</span>' : '';
            const src = ev.source ? '<span class="cred-audit-src">' + ev.source + '</span>' : '';
            return '<div class="cred-audit-entry">'
                + icon
                + '<strong class="cred-audit-svc">' + svc + '</strong>'
                + '<span class="cred-audit-type">' + typ + '</span>'
                + detail + src
                + '<span class="cred-audit-ts">' + ts + '</span>'
                + '</div>';
        }).join('');
    } catch (e) {
        list.innerHTML = '<div style="text-align:center;color:var(--error);padding:20px;">Failed to load audit events.</div>';
    }
}

async function loadCredentialCards() {
    const grid = document.getElementById('cred-cards-grid');
    grid.innerHTML = '<div class="loading"><div class="spinner"></div></div>';
    try {
        const res = await apiFetch(API + '/api/credentials/status');
        const data = await res.json();
        _credData = data.credentials || [];
        renderCredentialCards();
        updateCredSummary();
    } catch (e) {
        grid.innerHTML = '<div class="cred-empty">Could not load credential status.</div>';
    }
}

function updateCredSummary() {
    const total = _credData.length;
    const configured = _credData.filter(c => c.configured).length;
    const valid = _credData.filter(c => c.valid === true).length;
    const attention = _credData.filter(c => c.attention_needed).length;
    let text = configured + ' of ' + total + ' credentials configured';
    if (valid > 0) text += ' · ' + valid + ' valid';
    if (attention > 0) text += ' · <span class="cred-attention-count">' + attention + ' need' + (attention === 1 ? 's' : '') + ' attention</span>';
    document.getElementById('cred-summary-text').innerHTML = text;
}

function filterCredentials(cat) {
    _credFilter = cat;
    document.querySelectorAll('.cred-filter').forEach(b => {
        b.classList.toggle('active', b.dataset.cat === cat);
    });
    renderCredentialCards();
}

function renderCredentialCards() {
    const grid = document.getElementById('cred-cards-grid');
    const items = _credFilter === 'all' ? _credData : _credData.filter(c => c.category === _credFilter);
    if (items.length === 0) {
        grid.innerHTML = '<div class="cred-empty">No credentials in this category.</div>';
        return;
    }
    let html = '';
    for (const c of items) {
        const badge = _credBadge(c);
        const icon = _credIcon(c.category);
        let detail = '';
        if (c.last_validated) {
            detail = 'Validated ' + formatDate(c.last_validated, 'datetime');
        }
        if (c.last_error) {
            detail = '<span class="cred-error-detail">' + _escHtml(c.last_error) + '</span>';
        }
        if (!c.configured) {
            detail = c.doc_hint || 'Not configured';
        }
        html += '<div class="cred-card" data-cat="' + c.category + '">'
            + '<div class="cred-card-head">'
            + '<i class="fas ' + icon + ' cred-card-icon"></i>'
            + '<span class="cred-name">' + _escHtml(c.display_name) + '</span>'
            + badge
            + '</div>'
            + '<div class="cred-card-detail">' + detail + '</div>'
            + '<div class="cred-card-actions">'
            + '<button class="btn btn-secondary" onclick="testCredential(\'' + c.service_key + '\')"><i class="fas fa-vial" style="margin-right:3px"></i>Test</button>';
        // Action button based on reauth_type
        if (c.reauth_type === 'simple_token' || c.reauth_type === 'multi_field') {
            const label = c.configured ? (c.attention_needed ? 'Re-authorize' : 'Update') : 'Set Up';
            html += ' <button class="btn btn-primary" onclick="openCredUpdateModal(\'' + c.service_key + '\')">'
                + '<i class="fas fa-pen" style="margin-right:3px"></i>' + label + '</button>';
        } else if (c.reauth_type === 'oauth_redirect') {
            html += ' <button class="btn btn-primary" onclick="credOAuthRedirect(\'' + c.service_key + '\')">'
                + '<i class="fas fa-key" style="margin-right:3px"></i>Re-authorize</button>';
        } else if (c.reauth_type === 'wizard_only') {
            html += ' <button class="btn btn-secondary" onclick="credOpenWizard(\'' + c.service_key + '\')">'
                + '<i class="fas fa-magic" style="margin-right:3px"></i>Setup Wizard</button>';
        }
        if (c.doc_url) {
            html += ' <a href="' + c.doc_url + '" target="_blank" rel="noopener"><i class="fas fa-external-link-alt" style="margin-right:2px"></i>Docs</a>';
        }
        html += '</div></div>';
    }
    grid.innerHTML = html;
}

function _credBadge(c) {
    if (c.attention_needed) return '<span class="cred-badge attention">Needs Attention</span>';
    if (c.valid === true) return '<span class="cred-badge valid">Valid</span>';
    if (!c.configured) return '<span class="cred-badge unconfigured">Not Set Up</span>';
    if (c.valid === null || c.valid === undefined) return '<span class="cred-badge untested">Untested</span>';
    return '<span class="cred-badge attention">Invalid</span>';
}

function _credIcon(category) {
    const map = {
        llm: 'fa-brain', integrations: 'fa-plug', apis: 'fa-cloud',
        social: 'fa-share-alt', selfhosted: 'fa-server', channels: 'fa-comments',
        security: 'fa-shield-alt', mesh: 'fa-network-wired'
    };
    return map[category] || 'fa-key';
}

async function testCredential(serviceKey) {
    // Find the card and show a spinner on the badge
    const cards = document.querySelectorAll('.cred-card');
    let targetCard = null;
    for (const card of cards) {
        if (card.querySelector('.cred-name') && card.innerHTML.includes(serviceKey)) {
            targetCard = card;
            break;
        }
    }
    // Visual feedback
    if (targetCard) {
        const badge = targetCard.querySelector('.cred-badge');
        if (badge) { badge.textContent = 'Testing...'; badge.className = 'cred-badge untested'; }
    }
    try {
        const res = await apiFetch(API + '/api/credentials/validate/' + serviceKey, {method: 'POST'});
        const data = await res.json();
        // Update in-memory data
        const idx = _credData.findIndex(c => c.service_key === serviceKey);
        if (idx >= 0) {
            Object.assign(_credData[idx], data);
        }
        renderCredentialCards();
        updateCredSummary();
    } catch (e) {
        if (targetCard) {
            const badge = targetCard.querySelector('.cred-badge');
            if (badge) { badge.textContent = 'Error'; badge.className = 'cred-badge attention'; }
        }
    }
}

function _escHtml(s) {
    if (!s) return '';
    const d = document.createElement('div'); d.textContent = s; return d.innerHTML;
}

// ── Credential Update Modal ─────────────────────────────────
let _credModalServiceKey = null;

async function openCredUpdateModal(serviceKey) {
    _credModalServiceKey = serviceKey;
    const modal = document.getElementById('cred-update-modal');
    const errEl = document.getElementById('cred-modal-error');
    const okEl = document.getElementById('cred-modal-success');
    errEl.style.display = 'none';
    okEl.style.display = 'none';
    document.getElementById('cred-modal-save').disabled = false;
    document.getElementById('cred-modal-fields').innerHTML = '<div class="loading"><div class="spinner"></div></div>';
    modal.style.display = 'flex';

    try {
        const res = await apiFetch(API + '/api/credentials/fields/' + serviceKey);
        const data = await res.json();
        document.getElementById('cred-modal-title').textContent = 'Update ' + data.display_name;
        document.getElementById('cred-modal-hint').textContent = data.doc_hint || '';
        const docsLink = document.getElementById('cred-modal-docs');
        if (data.doc_url) { docsLink.href = data.doc_url; docsLink.style.display = ''; }
        else { docsLink.style.display = 'none'; }

        let html = '';
        for (const f of data.fields) {
            html += '<div class="form-group" style="margin-bottom:12px;">'
                + '<label style="display:block;font-size:0.82rem;color:var(--text-dim);margin-bottom:4px;">' + _escHtml(f.label) + '</label>'
                + '<input type="' + (f.is_secret ? 'password' : 'text') + '" '
                + 'id="cred-field-' + f.env_var + '" '
                + 'placeholder="' + (f.masked_value || f.env_var) + '" '
                + 'style="width:100%;padding:8px 10px;background:var(--bg-input);border:1px solid var(--border);border-radius:6px;color:var(--text-primary);font-size:0.9rem;" '
                + 'autocomplete="off">'
                + '</div>';
        }
        document.getElementById('cred-modal-fields').innerHTML = html;
    } catch (e) {
        document.getElementById('cred-modal-fields').innerHTML = '<div style="color:var(--text-dim)">Could not load fields.</div>';
    }
}

function closeCredModal() {
    document.getElementById('cred-update-modal').style.display = 'none';
    _credModalServiceKey = null;
}

async function saveCredModal() {
    if (!_credModalServiceKey) return;
    const errEl = document.getElementById('cred-modal-error');
    const okEl = document.getElementById('cred-modal-success');
    const saveBtn = document.getElementById('cred-modal-save');
    errEl.style.display = 'none';
    okEl.style.display = 'none';
    saveBtn.disabled = true;
    saveBtn.innerHTML = '<i class="fas fa-spinner fa-spin" style="margin-right:4px"></i>Testing...';

    // Collect values from inputs
    const inputs = document.querySelectorAll('#cred-modal-fields input');
    const values = {};
    let anyFilled = false;
    for (const inp of inputs) {
        const key = inp.id.replace('cred-field-', '');
        if (inp.value.trim()) {
            values[key] = inp.value.trim();
            anyFilled = true;
        }
    }
    if (!anyFilled) {
        errEl.textContent = 'Please enter at least one value.';
        errEl.style.display = '';
        saveBtn.disabled = false;
        saveBtn.innerHTML = '<i class="fas fa-check" style="margin-right:4px"></i>Save & Test';
        return;
    }

    try {
        const res = await apiFetch(API + '/api/credentials/update/' + _credModalServiceKey, {
            method: 'POST',
            headers: {'Content-Type': 'application/json'},
            body: JSON.stringify({values: values})
        });
        const data = await res.json();
        if (data.valid) {
            okEl.textContent = 'Saved and validated successfully!';
            okEl.style.display = '';
            saveBtn.innerHTML = '<i class="fas fa-check" style="margin-right:4px"></i>Saved!';
            setTimeout(() => { closeCredModal(); loadCredentialCards(); }, 1200);
        } else {
            errEl.textContent = data.error || data.last_error || 'Validation failed';
            errEl.style.display = '';
            saveBtn.disabled = false;
            saveBtn.innerHTML = '<i class="fas fa-check" style="margin-right:4px"></i>Save & Test';
        }
    } catch (e) {
        errEl.textContent = 'Request failed. Please try again.';
        errEl.style.display = '';
        saveBtn.disabled = false;
        saveBtn.innerHTML = '<i class="fas fa-check" style="margin-right:4px"></i>Save & Test';
    }
}

// Close modal on overlay click
document.getElementById('cred-update-modal').addEventListener('click', function(e) {
    if (e.target === this) closeCredModal();
});

function credOAuthRedirect(serviceKey) {
    // Map to existing Google OAuth flow or show instructions
    const googleServices = {google_workspace:1, google_calendar:1, google_gmail:1, google_drive:1, google_contacts:1};
    if (serviceKey in googleServices) {
        // Switch to Connect panel and start Google OAuth
        document.querySelector('[data-panel="connect"]').click();
        setTimeout(() => loadConnectWizard(), 200);
    } else {
        // For other OAuth services, open the update modal with instructions
        openCredUpdateModal(serviceKey);
    }
}

function credOpenWizard(serviceKey) {
    // Switch to Connect panel for the wizard-only services
    document.querySelector('[data-panel="connect"]').click();
    setTimeout(() => loadConnectWizard(), 200);
}

async function loadJobClasses() {
    const grid = document.getElementById('job-class-grid');
    if (!grid) return;
    try {
        const res = await apiFetch(API + '/api/config/job-class');
        const data = await res.json();
        const active = data.active || '';
        const classes = data.classes || [];
        let html = '<div class="jc-card' + (!active ? ' active' : '') + '" onclick="switchJobClass(\'\')">'
            + '<div class="jc-icon"><i class="fas fa-times-circle"></i></div>'
            + '<div class="jc-name">None</div>'
            + '<div class="jc-desc">No specialization</div></div>';
        for (const jc of classes) {
            const isActive = jc.key === active;
            html += '<div class="jc-card' + (isActive ? ' active' : '') + '" onclick="switchJobClass(\'' + jc.key + '\')">'
                + '<div class="jc-icon"><i class="fas ' + jc.icon + '"></i></div>'
                + '<div class="jc-name">' + jc.name + '</div>'
                + '<div class="jc-desc">' + jc.description + '</div></div>';
        }
        grid.innerHTML = html;
    } catch (e) {
        grid.innerHTML = '<div style="color:var(--text-dim);">Could not load job classes.</div>';
    }
}

async function switchJobClass(key) {
    try {
        const res = await apiFetch(API + '/api/config/job-class', {
            method: 'POST',
            headers: {'Content-Type': 'application/json'},
            body: JSON.stringify({job_class: key})
        });
        const data = await res.json();
        if (data.result) {
            loadJobClasses();
            updateWorkspaceNav();
        }
    } catch (e) {}
}


// ── Email Intelligence Settings ──────────────────────────────────────

async function loadEmailIntel() {
    const container = document.getElementById('email-intel-content');
    if (!container) return;

    try {
        const [configRes, statsRes] = await Promise.all([
            apiFetch(API + '/api/email/monitor/config'),
            apiFetch(API + '/api/email/monitor/stats'),
        ]);
        const config = await configRes.json();
        const stats = await statsRes.json();

        const lastCheck = stats.last_check_time
            ? formatDate(stats.last_check_time, 'time')
            : 'Never';

        let html = '';

        // Stats bar
        if (stats.total_sorted > 0) {
            html += '<div style="display:flex;gap:12px;margin-bottom:12px;flex-wrap:wrap">';
            html += '<div style="background:var(--bg-input);border-radius:8px;padding:8px 12px;font-size:0.82rem;flex:1;min-width:100px;text-align:center">'
                  + '<div style="font-size:1.3rem;font-weight:600">' + stats.total_sorted + '</div>Sorted</div>';
            if (stats.urgent) html += '<div style="background:var(--bg-input);border-radius:8px;padding:8px 12px;font-size:0.82rem;flex:1;min-width:80px;text-align:center">'
                  + '<div style="font-size:1.3rem;font-weight:600;color:var(--error)">' + stats.urgent + '</div>Urgent</div>';
            if (stats.action) html += '<div style="background:var(--bg-input);border-radius:8px;padding:8px 12px;font-size:0.82rem;flex:1;min-width:80px;text-align:center">'
                  + '<div style="font-size:1.3rem;font-weight:600;color:var(--warning)">' + stats.action + '</div>Action</div>';
            html += '<div style="background:var(--bg-input);border-radius:8px;padding:8px 12px;font-size:0.82rem;flex:1;min-width:80px;text-align:center">'
                  + '<div style="font-size:1.3rem;font-weight:600">' + stats.fyi + '</div>FYI</div>';
            html += '</div>';
        }

        // Training data stats
        const tr = stats.training || {};
        if (tr.total_pairs > 0 || tr.confirmed > 0) {
            html += '<div style="background:var(--bg-input);border-radius:8px;padding:8px 12px;margin-bottom:12px;font-size:0.82rem;display:flex;align-items:center;gap:12px;flex-wrap:wrap">';
            html += '<span><i class="fas fa-brain" style="color:var(--accent);margin-right:4px"></i><strong>Training Data:</strong></span>';
            html += '<span>' + (tr.total_pairs || 0) + ' pairs</span>';
            if (tr.confirmed) html += '<span style="color:var(--success)">' + tr.confirmed + ' confirmed \ud83d\udc4d</span>';
            if (tr.corrected) html += '<span style="color:var(--warning)">' + tr.corrected + ' corrected</span>';
            if (tr.high_confidence) html += '<span style="color:var(--text-dim)">' + tr.high_confidence + ' auto-harvested</span>';
            if (tr.ready_for_model) html += '<button class="browse-item-action" style="color:var(--success)" onclick="trainEmailModel(this)"><i class="fas fa-brain"></i> Train Model</button>';
            else html += '<span style="color:var(--text-dim)">Need ' + Math.max(0, 50 - (tr.total_pairs || 0)) + ' more for model</span>';
            html += '</div>';
        }

        // Monitor toggle
        html += '<div style="display:flex;align-items:center;justify-content:space-between;margin-bottom:12px">';
        html += '<div><strong>Background Sorting</strong><br><span style="font-size:0.8rem;color:var(--text-dim)">Last check: ' + escapeHtml(lastCheck) + '</span></div>';
        html += '<label style="display:flex;align-items:center;gap:8px;cursor:pointer">';
        html += '<span style="font-size:0.82rem;color:var(--text-dim)">' + (config.enabled ? 'Active' : 'Off') + '</span>';
        html += '<input type="checkbox" ' + (config.enabled ? 'checked' : '') + ' onchange="toggleEmailMonitor(this.checked)" style="width:18px;height:18px;cursor:pointer">';
        html += '</label></div>';

        // Interval
        html += '<div style="display:flex;align-items:center;justify-content:space-between;margin-bottom:12px">';
        html += '<div><strong>Sort Interval</strong><br><span style="font-size:0.8rem;color:var(--text-dim)">How often to check for new email</span></div>';
        html += '<select onchange="updateEmailMonitorConfig({interval_minutes: parseInt(this.value)})" style="padding:4px 8px">';
        [5, 10, 15, 30, 60].forEach(m => {
            html += '<option value="' + m + '"' + (config.interval_minutes === m ? ' selected' : '') + '>' + m + ' min</option>';
        });
        html += '</select></div>';

        // Quiet hours
        html += '<div style="display:flex;align-items:center;justify-content:space-between;margin-bottom:12px">';
        html += '<div><strong>Quiet Hours</strong><br><span style="font-size:0.8rem;color:var(--text-dim)">No alerts during these hours</span></div>';
        html += '<div style="display:flex;gap:4px;align-items:center">';
        html += '<input type="time" value="' + (config.quiet_hours_start || '22:00') + '" onchange="updateEmailMonitorConfig({quiet_hours_start: this.value})" style="padding:3px 6px;font-size:0.85rem">';
        html += '<span style="color:var(--text-dim)">to</span>';
        html += '<input type="time" value="' + (config.quiet_hours_end || '07:00') + '" onchange="updateEmailMonitorConfig({quiet_hours_end: this.value})" style="padding:3px 6px;font-size:0.85rem">';
        html += '</div></div>';

        // Divider
        html += '<hr style="border:none;border-top:1px solid var(--border, rgba(255,255,255,0.05));margin:16px 0">';

        // Smart Mode
        html += '<div style="display:flex;align-items:center;justify-content:space-between;margin-bottom:12px">';
        html += '<div><strong>Smart Mode</strong> <span style="font-size:0.75rem;background:var(--accent);color:#fff;padding:1px 6px;border-radius:3px">AI</span>';
        html += '<br><span style="font-size:0.8rem;color:var(--text-dim)">Uses AI for ambiguous emails (~50 tokens each)</span></div>';
        html += '<label style="display:flex;align-items:center;gap:8px;cursor:pointer">';
        html += '<span style="font-size:0.82rem;color:var(--text-dim)">' + (config.smart_mode_enabled ? 'On' : 'Off') + '</span>';
        html += '<input type="checkbox" ' + (config.smart_mode_enabled ? 'checked' : '') + ' onchange="updateEmailMonitorConfig({smart_mode_enabled: this.checked})" style="width:18px;height:18px;cursor:pointer">';
        html += '</label></div>';

        if (config.smart_mode_enabled) {
            // Batch size
            html += '<div style="display:flex;align-items:center;justify-content:space-between;margin-bottom:12px;padding-left:12px">';
            html += '<div><span style="font-size:0.85rem">Emails per batch</span></div>';
            html += '<select onchange="updateEmailMonitorConfig({smart_batch_size: parseInt(this.value)})" style="padding:4px 8px">';
            [1, 2, 3, 5].forEach(n => {
                html += '<option value="' + n + '"' + (config.smart_batch_size === n ? ' selected' : '') + '>' + n + '</option>';
            });
            html += '</select></div>';

            // Token budget
            const used = stats.smart_tokens_used_today || 0;
            const budget = config.smart_daily_budget_tokens || 1000;
            const pct = Math.min(100, Math.round(used / budget * 100));
            html += '<div style="padding-left:12px;margin-bottom:8px">';
            html += '<div style="display:flex;justify-content:space-between;font-size:0.82rem;margin-bottom:4px">';
            html += '<span>Daily token budget</span><span>' + used + ' / ' + budget + '</span></div>';
            html += '<div style="background:var(--bg-input);border-radius:4px;height:6px;overflow:hidden">';
            html += '<div style="background:var(--accent);height:100%;width:' + pct + '%;transition:width 0.3s"></div>';
            html += '</div></div>';
        }

        container.innerHTML = html;
        // Load all sub-sections below main settings
        loadQuickSetup();
        loadEmailSuggestions();
        loadCustomCategories();
        loadVipAndTopics();
        loadSuggestedVips();
        loadContactTiers();
    } catch(e) {
        container.innerHTML = '<p style="color:var(--text-dim);font-size:0.85rem">Email Intelligence unavailable — connect email in Settings first.</p>';
    }
}

async function toggleEmailMonitor(enabled) {
    try {
        await apiFetch(API + '/api/email/monitor/config', {
            method: 'POST',
            headers: {'Content-Type': 'application/json'},
            body: JSON.stringify({enabled}),
        });
        showToast(enabled ? 'Email sorting enabled' : 'Email sorting paused', 'success');
        loadEmailIntel();
    } catch(e) { showToast('Failed: ' + e.message, 'error'); }
}

async function updateEmailMonitorConfig(updates) {
    try {
        await apiFetch(API + '/api/email/monitor/config', {
            method: 'POST',
            headers: {'Content-Type': 'application/json'},
            body: JSON.stringify(updates),
        });
        loadEmailIntel();
    } catch(e) { showToast('Failed: ' + e.message, 'error'); }
}

// ── VIP Senders & Topic Flags Management ─────────────────────────────

async function loadVipAndTopics() {
    // Inject into the email intel card after the main settings
    const container = document.getElementById('email-intel-content');
    if (!container) return;

    // Append VIP + Topics sections below existing settings
    let existing = container.querySelector('#email-vip-topics');
    if (!existing) {
        existing = document.createElement('div');
        existing.id = 'email-vip-topics';
        container.appendChild(existing);
    }

    try {
        const [vipRes, topicRes] = await Promise.all([
            apiFetch(API + '/api/email/vip-senders'),
            apiFetch(API + '/api/email/topic-flags'),
        ]);
        const vipData = await vipRes.json();
        const topicData = await topicRes.json();
        const vips = vipData.vips || [];
        const flags = topicData.flags || [];

        let html = '<hr style="border:none;border-top:1px solid var(--border, rgba(255,255,255,0.05));margin:16px 0">';

        // VIP Senders
        html += '<div style="margin-bottom:16px">';
        html += '<div style="display:flex;justify-content:space-between;align-items:center;margin-bottom:8px">';
        html += '<strong>VIP Senders</strong>';
        html += '<span style="font-size:0.78rem;color:var(--text-dim)">' + vips.length + ' sender' + (vips.length !== 1 ? 's' : '') + '</span>';
        html += '</div>';
        html += '<p style="font-size:0.8rem;color:var(--text-dim);margin:0 0 8px">Emails from these senders are always prioritized. Add emails or domains (e.g., @gjl.org).</p>';

        // Add input
        html += '<div style="display:flex;gap:6px;margin-bottom:8px">';
        html += '<input type="text" id="vip-add-input" placeholder="email@example.com or @domain.org" style="flex:1;font-size:0.85rem" onkeydown="if(event.key===\'Enter\')addVipSender()">';
        html += '<button class="btn btn-primary" style="font-size:0.78rem;padding:4px 10px" onclick="addVipSender()"><i class="fas fa-plus"></i> Add</button>';
        html += '<button class="btn btn-secondary" style="font-size:0.78rem;padding:4px 10px" onclick="browseSyncGoogleContacts(this)"><i class="fas fa-address-book"></i> Sync Contacts</button>';
        html += '</div>';

        // VIP list
        if (vips.length) {
            html += '<div style="display:flex;flex-wrap:wrap;gap:6px">';
            vips.forEach(v => {
                html += '<span style="display:inline-flex;align-items:center;gap:4px;background:var(--bg-input);padding:3px 8px;border-radius:12px;font-size:0.8rem">';
                html += '<i class="fas fa-star" style="color:var(--accent);font-size:0.7rem"></i>';
                html += escapeHtml(v);
                html += '<button style="background:none;border:none;color:var(--text-dim);cursor:pointer;padding:0 2px;font-size:0.75rem" onclick="removeVipSender(\'' + escapeHtml(v).replace(/'/g, "\\'") + '\')" title="Remove">&times;</button>';
                html += '</span>';
            });
            html += '</div>';
        } else {
            html += '<p style="font-size:0.8rem;color:var(--text-dim);font-style:italic;margin:4px 0">No VIP senders yet. Add contacts or sync from Google.</p>';
        }
        html += '</div>';

        // Topic Flags
        html += '<div style="margin-bottom:8px">';
        html += '<div style="display:flex;justify-content:space-between;align-items:center;margin-bottom:8px">';
        html += '<strong>Topic Flags</strong>';
        html += '<span style="font-size:0.78rem;color:var(--text-dim)">' + flags.length + ' flag' + (flags.length !== 1 ? 's' : '') + '</span>';
        html += '</div>';
        html += '<p style="font-size:0.8rem;color:var(--text-dim);margin:0 0 8px">Emails containing these keywords are auto-escalated to urgent/action priority.</p>';

        // Add input
        html += '<div style="display:flex;gap:6px;margin-bottom:8px">';
        html += '<input type="text" id="topic-add-input" placeholder="grant deadline, board meeting, donation" style="flex:1;font-size:0.85rem" onkeydown="if(event.key===\'Enter\')addTopicFlag()">';
        html += '<select id="topic-add-priority" style="font-size:0.85rem;padding:4px"><option value="action">Action</option><option value="urgent">Urgent</option></select>';
        html += '<button class="btn btn-primary" style="font-size:0.78rem;padding:4px 10px" onclick="addTopicFlag()"><i class="fas fa-plus"></i> Add</button>';
        html += '</div>';

        // Topic list
        if (flags.length) {
            html += '<div style="display:flex;flex-wrap:wrap;gap:6px">';
            flags.forEach(f => {
                const keyword = typeof f === 'string' ? f : (f.keyword || f);
                const pri = typeof f === 'object' ? (f.priority || 'action') : 'action';
                const priEmoji = pri === 'urgent' ? '\ud83d\udd34' : '\ud83d\udfe1';
                html += '<span style="display:inline-flex;align-items:center;gap:4px;background:var(--bg-input);padding:3px 8px;border-radius:12px;font-size:0.8rem">';
                html += priEmoji + ' ';
                html += escapeHtml(keyword);
                html += '<button style="background:none;border:none;color:var(--text-dim);cursor:pointer;padding:0 2px;font-size:0.75rem" onclick="removeTopicFlag(\'' + escapeHtml(keyword).replace(/'/g, "\\'") + '\')" title="Remove">&times;</button>';
                html += '</span>';
            });
            html += '</div>';
        } else {
            html += '<p style="font-size:0.8rem;color:var(--text-dim);font-style:italic;margin:4px 0">No topic flags yet. Add keywords that should trigger urgent/action priority.</p>';
        }
        html += '</div>';

        existing.innerHTML = html;
    } catch(e) {
        existing.innerHTML = '<p style="color:var(--text-dim);font-size:0.85rem">VIP/topic settings unavailable.</p>';
    }
}

async function addVipSender() {
    const input = document.getElementById('vip-add-input');
    const sender = (input.value || '').trim();
    if (!sender) { showToast('Enter an email or domain', 'error'); return; }
    try {
        await apiFetch(API + '/api/email/vip-senders', {
            method: 'POST',
            headers: {'Content-Type': 'application/json'},
            body: JSON.stringify({sender}),
        });
        input.value = '';
        showToast(sender + ' added as VIP', 'success');
        loadVipAndTopics();
    } catch(e) { showToast('Failed: ' + e.message, 'error'); }
}

async function removeVipSender(sender) {
    try {
        await apiFetch(API + '/api/email/vip-senders', {
            method: 'DELETE',
            headers: {'Content-Type': 'application/json'},
            body: JSON.stringify({sender}),
        });
        showToast(sender + ' removed', 'success');
        loadVipAndTopics();
    } catch(e) { showToast('Failed: ' + e.message, 'error'); }
}

async function addTopicFlag() {
    const input = document.getElementById('topic-add-input');
    const keyword = (input.value || '').trim();
    const priority = document.getElementById('topic-add-priority').value;
    if (!keyword) { showToast('Enter a keyword', 'error'); return; }
    try {
        await apiFetch(API + '/api/email/topic-flags', {
            method: 'POST',
            headers: {'Content-Type': 'application/json'},
            body: JSON.stringify({keyword, priority}),
        });
        input.value = '';
        showToast('"' + keyword + '" flagged as ' + priority, 'success');
        loadVipAndTopics();
    } catch(e) { showToast('Failed: ' + e.message, 'error'); }
}

async function removeTopicFlag(keyword) {
    try {
        await apiFetch(API + '/api/email/topic-flags', {
            method: 'DELETE',
            headers: {'Content-Type': 'application/json'},
            body: JSON.stringify({keyword}),
        });
        showToast('"' + keyword + '" removed', 'success');
        loadVipAndTopics();
    } catch(e) { showToast('Failed: ' + e.message, 'error'); }
}

// ── Suggested VIPs (from engagement data) ─────────────────────────────

async function loadSuggestedVips() {
    const container = document.getElementById('email-vip-topics');
    if (!container) return;

    let existing = container.querySelector('#email-suggested-vips');
    if (!existing) {
        existing = document.createElement('div');
        existing.id = 'email-suggested-vips';
        container.appendChild(existing);
    }

    try {
        const [engRes, vipRes] = await Promise.all([
            apiFetch(API + '/api/email/engagement/top'),
            apiFetch(API + '/api/email/vip-senders'),
        ]);
        const engData = await engRes.json();
        const vipData = await vipRes.json();
        const vips = new Set((vipData.vips || []).map(v => v.toLowerCase()));
        const stats = engData.stats || {};

        // Find high-engagement senders not already VIP
        const suggestions = (engData.top || []).filter(s =>
            s.engagement_score > 1.0 && !vips.has(s.sender.toLowerCase())
        ).slice(0, 5);

        // Find low-engagement senders to suggest marking as Promotional
        let lowEngHtml = '';
        try {
            const lowRes = await apiFetch(API + '/api/email/engagement/top');
            const lowData = await lowRes.json();
            // Get all senders, filter for low engagement + high receive
            const allSenders = lowData.top || [];
            // We need the low engaged ones — engagement/top returns highest first
            // Use stats to show the overview
        } catch(e) {}

        let html = '';
        if (suggestions.length || stats.total_senders) {
            html += '<hr style="border:none;border-top:1px solid var(--border, rgba(255,255,255,0.05));margin:16px 0">';

            // Engagement stats
            if (stats.total_senders) {
                html += '<div style="display:flex;gap:12px;margin-bottom:12px;flex-wrap:wrap">';
                html += '<div style="background:var(--bg-input);border-radius:8px;padding:6px 10px;font-size:0.8rem;text-align:center">'
                      + '<div style="font-weight:600">' + stats.total_senders + '</div>Senders tracked</div>';
                html += '<div style="background:var(--bg-input);border-radius:8px;padding:6px 10px;font-size:0.8rem;text-align:center">'
                      + '<div style="font-weight:600;color:var(--success,#2ecc71)">' + stats.high + '</div>High engagement</div>';
                html += '<div style="background:var(--bg-input);border-radius:8px;padding:6px 10px;font-size:0.8rem;text-align:center">'
                      + '<div style="font-weight:600;color:var(--accent)">' + stats.medium + '</div>Medium</div>';
                html += '<div style="background:var(--bg-input);border-radius:8px;padding:6px 10px;font-size:0.8rem;text-align:center">'
                      + '<div style="font-weight:600;color:var(--text-dim)">' + stats.low + '</div>Low/ignored</div>';
                html += '</div>';
            }

            // Suggested VIPs
            if (suggestions.length) {
                html += '<div style="margin-bottom:8px">';
                html += '<strong>Suggested VIPs</strong>';
                html += '<p style="font-size:0.8rem;color:var(--text-dim);margin:4px 0 8px">Senders you interact with frequently that aren\'t VIPs yet:</p>';
                suggestions.forEach(s => {
                    const opens = s.opened || 0;
                    const replies = s.replied || 0;
                    const total = s.total_received || 0;
                    html += '<div style="display:flex;align-items:center;gap:8px;padding:6px 8px;background:var(--bg-input);border-radius:6px;margin-bottom:4px">';
                    html += '<span style="flex:1;font-size:0.85rem">' + escapeHtml(s.sender) + '</span>';
                    html += '<span style="font-size:0.75rem;color:var(--text-dim)">' + replies + ' replies, ' + opens + ' opens / ' + total + ' received</span>';
                    html += '<button class="browse-item-action" onclick="addVipFromSuggestion(\'' + escapeHtml(s.sender).replace(/'/g, "\\'") + '\', this)"><i class="fas fa-star"></i> Add VIP</button>';
                    html += '</div>';
                });
                html += '</div>';
            }
        }

        existing.innerHTML = html;
    } catch(e) {
        existing.innerHTML = '';
    }
}

async function addVipFromSuggestion(sender, btn) {
    try {
        await apiFetch(API + '/api/email/vip-senders', {
            method: 'POST',
            headers: {'Content-Type': 'application/json'},
            body: JSON.stringify({sender}),
        });
        btn.innerHTML = '<i class="fas fa-check" style="color:var(--success)"></i>';
        btn.disabled = true;
        showToast(sender + ' added as VIP', 'success');
    } catch(e) { showToast('Failed: ' + e.message, 'error'); }
}

// ── Contact Relationship Tiers ─────────────────────────────────────

async function loadContactTiers() {
    const container = document.getElementById('email-vip-topics');
    if (!container) return;

    let existing = container.querySelector('#email-contact-tiers');
    if (!existing) {
        existing = document.createElement('div');
        existing.id = 'email-contact-tiers';
        container.appendChild(existing);
    }

    try {
        const res = await apiFetch(API + '/api/contacts/by-tier');
        const data = await res.json();
        const byTier = data.by_tier || {};
        const total = (data.contacts || []).length;

        if (!total) {
            existing.innerHTML = '';
            return;
        }

        const tierMeta = {
            close: {emoji: '\ud83d\udc9a', label: 'Close', color: 'var(--success,#2ecc71)'},
            professional: {emoji: '\ud83d\udcbc', label: 'Professional', color: 'var(--accent)'},
            acquaintance: {emoji: '\ud83d\udc4b', label: 'Acquaintance', color: 'var(--text-dim)'},
        };

        let html = '<hr style="border:none;border-top:1px solid var(--border, rgba(255,255,255,0.05));margin:16px 0">';
        html += '<div style="display:flex;justify-content:space-between;align-items:center;margin-bottom:8px">';
        html += '<strong>Contact Relationship Tiers</strong>';
        html += '<button class="browse-item-action" onclick="refreshContactTiers(this)" title="Refresh tiers from engagement data"><i class="fas fa-sync-alt"></i> Refresh</button>';
        html += '</div>';
        html += '<p style="font-size:0.8rem;color:var(--text-dim);margin:0 0 8px">Auto-assigned from engagement data. Click a tier badge to override.</p>';

        // Tier summary
        html += '<div style="display:flex;gap:8px;margin-bottom:12px;flex-wrap:wrap">';
        for (const [tier, meta] of Object.entries(tierMeta)) {
            const count = (byTier[tier] || []).length;
            html += '<div style="background:var(--bg-input);border-radius:8px;padding:6px 12px;font-size:0.82rem;display:flex;align-items:center;gap:6px">';
            html += meta.emoji + ' <strong>' + count + '</strong> ' + meta.label;
            html += '</div>';
        }
        html += '</div>';

        // Show close + professional contacts (not acquaintance — too many)
        for (const tier of ['close', 'professional']) {
            const contacts = byTier[tier] || [];
            if (!contacts.length) continue;
            const meta = tierMeta[tier];

            html += '<div style="margin-bottom:8px">';
            html += '<div style="font-size:0.82rem;font-weight:500;margin-bottom:4px">' + meta.emoji + ' ' + meta.label + ' (' + contacts.length + ')</div>';
            contacts.slice(0, 10).forEach(c => {
                html += '<div style="display:flex;align-items:center;gap:6px;padding:3px 8px;font-size:0.82rem">';
                html += '<span style="flex:1">' + escapeHtml(c.name || '') + '</span>';
                html += '<span style="color:var(--text-dim);font-size:0.75rem">' + escapeHtml(c.email || '') + '</span>';
                if (c.organization) html += '<span style="color:var(--text-dim);font-size:0.75rem">' + escapeHtml(c.organization) + '</span>';
                // Tier override dropdown
                html += '<select style="font-size:0.72rem;padding:1px 4px" onchange="setContactTier(\'' + c.id + '\', this.value)">';
                for (const [t, m] of Object.entries(tierMeta)) {
                    html += '<option value="' + t + '"' + (tier === t ? ' selected' : '') + '>' + m.label + '</option>';
                }
                html += '</select>';
                html += '</div>';
            });
            if (contacts.length > 10) {
                html += '<div style="font-size:0.75rem;color:var(--text-dim);padding:3px 8px">... and ' + (contacts.length - 10) + ' more</div>';
            }
            html += '</div>';
        }

        existing.innerHTML = html;
    } catch(e) {
        existing.innerHTML = '';
    }
}

async function refreshContactTiers(btn) {
    if (btn) { btn.disabled = true; btn.innerHTML = '<i class="fas fa-spinner fa-spin"></i>'; }
    try {
        const r = await apiFetch(API + '/api/contacts/tiers/refresh', {method: 'POST'});
        const d = await r.json();
        showToast('Updated ' + (d.updated || 0) + ' contact tiers', 'success');
        loadContactTiers();
    } catch(e) { showToast('Failed: ' + e.message, 'error'); }
    if (btn) { btn.disabled = false; btn.innerHTML = '<i class="fas fa-sync-alt"></i> Refresh'; }
}

async function setContactTier(contactId, tier) {
    try {
        await apiFetch(API + '/api/contacts/tiers/' + contactId, {
            method: 'PUT',
            headers: {'Content-Type': 'application/json'},
            body: JSON.stringify({tier}),
        });
        showToast('Tier updated', 'success');
    } catch(e) { showToast('Failed: ' + e.message, 'error'); }
}

// ── TF-IDF Model Training ─────────────────────────────────────

async function trainEmailModel(btn) {
    btn.disabled = true;
    btn.innerHTML = '<i class="fas fa-spinner fa-spin"></i> Training...';
    try {
        const r = await apiFetch(API + '/api/email/model/train', {method: 'POST'});
        const d = await r.json();
        if (d.trained) {
            showToast('Model trained: ' + d.docs + ' docs, ' + Math.round(d.accuracy * 100) + '% accuracy', 'success');
        } else {
            showToast(d.error || 'Training failed', 'error');
        }
        loadEmailIntel();
    } catch(e) { showToast('Training failed: ' + e.message, 'error'); }
    btn.disabled = false;
    btn.innerHTML = '<i class="fas fa-brain"></i> Train Model';
}

// ── Proactive Suggestions ─────────────────────────────────────

async function loadEmailSuggestions() {
    const container = document.getElementById('email-intel-content');
    if (!container) return;

    let existing = container.querySelector('#email-suggestions');
    if (!existing) {
        existing = document.createElement('div');
        existing.id = 'email-suggestions';
        container.insertBefore(existing, container.firstChild);
    }

    try {
        const res = await apiFetch(API + '/api/email/suggestions');
        const data = await res.json();
        const suggestions = data.suggestions || [];

        if (!suggestions.length) {
            existing.innerHTML = '';
            return;
        }

        const actionIcons = {
            add_vip: 'fa-star',
            mark_promotional: 'fa-tag',
            mark_domain_promotional: 'fa-tag',
            train_model: 'fa-brain',
            retrain_model: 'fa-brain',
            sync_contacts: 'fa-address-book',
        };

        let html = '<div style="margin-bottom:12px">';
        html += '<div style="font-weight:600;font-size:0.85rem;margin-bottom:6px"><i class="fas fa-lightbulb" style="color:var(--warning);margin-right:4px"></i>Suggestions</div>';

        suggestions.forEach((s, i) => {
            const icon = actionIcons[s.action] || 'fa-magic';
            html += '<div style="display:flex;align-items:center;gap:8px;padding:8px 10px;background:var(--bg-input);border-radius:6px;margin-bottom:4px">';
            html += '<i class="fas ' + icon + '" style="color:var(--accent);flex-shrink:0"></i>';
            html += '<div style="flex:1;min-width:0">';
            html += '<div style="font-size:0.85rem;font-weight:500">' + escapeHtml(s.title) + '</div>';
            html += '<div style="font-size:0.75rem;color:var(--text-dim)">' + escapeHtml(s.description) + '</div>';
            html += '</div>';
            html += '<button class="browse-item-action" onclick="applySuggestion(' + JSON.stringify(s).replace(/"/g, '&quot;') + ',this)" style="white-space:nowrap"><i class="fas fa-check"></i> Apply</button>';
            html += '<button class="browse-item-action" onclick="this.closest(\'div[style]\').style.display=\'none\'" style="padding:2px 4px" title="Dismiss">&times;</button>';
            html += '</div>';
        });

        html += '</div>';
        existing.innerHTML = html;
    } catch(e) {
        existing.innerHTML = '';
    }
}

async function applySuggestion(suggestion, btn) {
    btn.disabled = true;
    btn.innerHTML = '<i class="fas fa-spinner fa-spin"></i>';
    try {
        const r = await apiFetch(API + '/api/email/suggestions/apply', {
            method: 'POST',
            headers: {'Content-Type': 'application/json'},
            body: JSON.stringify({action: suggestion.action, action_data: suggestion.action_data}),
        });
        const d = await r.json();
        showToast(d.result || 'Applied!', 'success');
        btn.innerHTML = '<i class="fas fa-check" style="color:var(--success)"></i>';
        // Refresh suggestions
        setTimeout(() => loadEmailSuggestions(), 1000);
    } catch(e) {
        showToast('Failed: ' + e.message, 'error');
        btn.disabled = false;
        btn.innerHTML = '<i class="fas fa-check"></i> Apply';
    }
}

// ── Custom Email Categories ─────────────────────────────────────

async function loadCustomCategories() {
    const container = document.getElementById('email-intel-content');
    if (!container) return;

    let existing = container.querySelector('#email-custom-cats');
    if (!existing) {
        existing = document.createElement('div');
        existing.id = 'email-custom-cats';
        container.appendChild(existing);
    }

    try {
        const res = await apiFetch(API + '/api/email/custom-categories');
        const data = await res.json();
        const cats = data.categories || [];

        let html = '<hr style="border:none;border-top:1px solid var(--border, rgba(255,255,255,0.05));margin:16px 0">';
        html += '<div style="display:flex;justify-content:space-between;align-items:center;margin-bottom:8px">';
        html += '<strong>Custom Categories</strong>';
        html += '<button class="browse-item-action" onclick="showAddCategoryForm()"><i class="fas fa-plus"></i> New Category</button>';
        html += '</div>';
        html += '<p style="font-size:0.8rem;color:var(--text-dim);margin:0 0 8px">Create your own categories with keywords. Emails matching any keyword get sorted into that category.</p>';

        // Add category form (hidden by default)
        html += '<div id="custom-cat-form" style="display:none;background:var(--bg-input);border-radius:8px;padding:12px;margin-bottom:12px">';
        html += '<div style="display:flex;gap:6px;margin-bottom:8px">';
        html += '<input type="text" id="custom-cat-name" placeholder="Category name (e.g., Role Playing)" style="flex:1;font-size:0.85rem">';
        html += '</div>';
        html += '<div style="margin-bottom:8px">';
        html += '<input type="text" id="custom-cat-keywords" placeholder="Keywords, comma separated (e.g., D&D, gaming, magic the gathering)" style="width:100%;font-size:0.85rem">';
        html += '</div>';
        html += '<div style="display:flex;gap:6px;justify-content:flex-end">';
        html += '<button class="btn btn-secondary" onclick="document.getElementById(\'custom-cat-form\').style.display=\'none\'">Cancel</button>';
        html += '<button class="btn btn-primary" onclick="saveCustomCategory()"><i class="fas fa-check"></i> Create</button>';
        html += '</div></div>';

        // List existing
        if (cats.length) {
            cats.forEach(c => {
                html += '<div style="display:flex;align-items:center;gap:8px;padding:8px 10px;background:var(--bg-input);border-radius:6px;margin-bottom:4px">';
                html += '<span style="font-size:1.1rem">\ud83c\udff7\ufe0f</span>';
                html += '<div style="flex:1">';
                html += '<div style="font-weight:500;font-size:0.85rem">' + escapeHtml(c.name) + '</div>';
                html += '<div style="font-size:0.75rem;color:var(--text-dim)">' + escapeHtml((c.keywords || []).join(', ')) + '</div>';
                html += '</div>';
                html += '<button class="browse-item-action danger" onclick="deleteCustomCategory(\'' + escapeHtml(c.name).replace(/'/g, "\\'") + '\')" title="Delete"><i class="fas fa-trash"></i></button>';
                html += '</div>';
            });
        }

        existing.innerHTML = html;
    } catch(e) {
        existing.innerHTML = '';
    }
}

function showAddCategoryForm() {
    const form = document.getElementById('custom-cat-form');
    if (form) {
        form.style.display = '';
        document.getElementById('custom-cat-name').value = '';
        document.getElementById('custom-cat-keywords').value = '';
        document.getElementById('custom-cat-name').focus();
    }
}

async function saveCustomCategory() {
    const name = (document.getElementById('custom-cat-name').value || '').trim();
    const keywordsStr = (document.getElementById('custom-cat-keywords').value || '').trim();

    if (!name) { showToast('Enter a category name', 'error'); return; }
    if (!keywordsStr) { showToast('Enter at least one keyword', 'error'); return; }

    const keywords = keywordsStr.split(',').map(k => k.trim()).filter(k => k);

    try {
        const r = await apiFetch(API + '/api/email/custom-categories', {
            method: 'POST',
            headers: {'Content-Type': 'application/json'},
            body: JSON.stringify({name, keywords}),
        });
        const d = await r.json();
        showToast((d.created ? 'Created' : 'Updated') + ': ' + name, 'success');
        document.getElementById('custom-cat-form').style.display = 'none';
        loadCustomCategories();
    } catch(e) { showToast('Failed: ' + e.message, 'error'); }
}

async function deleteCustomCategory(name) {
    try {
        await apiFetch(API + '/api/email/custom-categories', {
            method: 'DELETE',
            headers: {'Content-Type': 'application/json'},
            body: JSON.stringify({name}),
        });
        showToast(name + ' deleted', 'success');
        loadCustomCategories();
    } catch(e) { showToast('Failed: ' + e.message, 'error'); }
}

// ── Quick Setup (Work Domain + Family) ─────────────────────────

async function loadQuickSetup() {
    const container = document.getElementById('email-intel-content');
    if (!container) return;

    let existing = container.querySelector('#email-quick-setup');
    if (!existing) {
        existing = document.createElement('div');
        existing.id = 'email-quick-setup';
        container.insertBefore(existing, container.firstChild);
    }

    try {
        const res = await apiFetch(API + '/api/email/quick-setup');
        const data = await res.json();
        const workDomains = data.work_domains || [];
        const familyEmails = data.family_emails || [];

        // Only show if not yet configured
        if (workDomains.length && familyEmails.length) {
            // Show compact summary
            let html = '<div style="background:var(--bg-input);border-radius:8px;padding:10px 12px;margin-bottom:12px;font-size:0.82rem;display:flex;align-items:center;gap:12px;flex-wrap:wrap">';
            html += '<span><i class="fas fa-building" style="color:var(--accent);margin-right:4px"></i><strong>Work:</strong> ';
            html += workDomains.map(d => '@' + escapeHtml(d)).join(', ');
            html += ' <button class="browse-item-action" onclick="addQuickSetupItem(\'work\')" style="font-size:0.7rem">+ Add</button></span>';
            html += '<span><i class="fas fa-home" style="color:var(--success);margin-right:4px"></i><strong>Family:</strong> ';
            html += familyEmails.map(e => escapeHtml(e)).join(', ');
            html += ' <button class="browse-item-action" onclick="addQuickSetupItem(\'family\')" style="font-size:0.7rem">+ Add</button></span>';
            html += '</div>';
            existing.innerHTML = html;
            return;
        }

        // Show setup form
        let html = '<div style="background:linear-gradient(135deg,rgba(99,102,241,0.1),rgba(16,185,129,0.1));border:1px solid var(--accent);border-radius:8px;padding:14px;margin-bottom:12px">';
        html += '<div style="font-weight:600;margin-bottom:6px"><i class="fas fa-magic" style="color:var(--accent);margin-right:4px"></i>Quick Setup</div>';
        html += '<p style="font-size:0.82rem;color:var(--text-dim);margin:0 0 10px">Help the email sorter identify your important emails right away.</p>';

        // Work domain
        html += '<div style="display:flex;gap:6px;align-items:center;margin-bottom:8px">';
        html += '<i class="fas fa-building" style="color:var(--accent);width:20px;text-align:center"></i>';
        html += '<input type="text" id="qs-work-domain" placeholder="Your work domain (e.g., gjl.org)" style="flex:1;font-size:0.85rem">';
        html += '<button class="btn btn-primary" style="font-size:0.78rem;padding:4px 10px" onclick="saveQuickSetup(\'work\')">Add</button>';
        html += '</div>';
        if (workDomains.length) {
            html += '<div style="margin-left:26px;margin-bottom:8px;display:flex;gap:4px;flex-wrap:wrap">';
            workDomains.forEach(d => {
                html += '<span style="font-size:0.78rem;padding:2px 6px;background:var(--bg-input);border-radius:10px">@' + escapeHtml(d);
                html += ' <button style="background:none;border:none;color:var(--text-dim);cursor:pointer;font-size:0.7rem;padding:0 2px" onclick="removeQuickSetup(\'work\',\'' + escapeHtml(d) + '\')">&times;</button></span>';
            });
            html += '</div>';
        }

        // Family emails
        html += '<div style="display:flex;gap:6px;align-items:center;margin-bottom:8px">';
        html += '<i class="fas fa-home" style="color:var(--success);width:20px;text-align:center"></i>';
        html += '<input type="text" id="qs-family-email" placeholder="Family member email (e.g., sister@gmail.com)" style="flex:1;font-size:0.85rem">';
        html += '<button class="btn btn-primary" style="font-size:0.78rem;padding:4px 10px" onclick="saveQuickSetup(\'family\')">Add</button>';
        html += '</div>';
        if (familyEmails.length) {
            html += '<div style="margin-left:26px;margin-bottom:4px;display:flex;gap:4px;flex-wrap:wrap">';
            familyEmails.forEach(e => {
                html += '<span style="font-size:0.78rem;padding:2px 6px;background:var(--bg-input);border-radius:10px">' + escapeHtml(e);
                html += ' <button style="background:none;border:none;color:var(--text-dim);cursor:pointer;font-size:0.7rem;padding:0 2px" onclick="removeQuickSetup(\'family\',\'' + escapeHtml(e) + '\')">&times;</button></span>';
            });
            html += '</div>';
        }

        html += '</div>';
        existing.innerHTML = html;
    } catch(e) {
        existing.innerHTML = '';
    }
}

async function saveQuickSetup(type) {
    if (type === 'work') {
        const input = document.getElementById('qs-work-domain');
        const val = (input.value || '').trim();
        if (!val) { showToast('Enter a work domain', 'error'); return; }
        await apiFetch(API + '/api/email/quick-setup', {
            method: 'POST',
            headers: {'Content-Type': 'application/json'},
            body: JSON.stringify({work_domain: val}),
        });
        input.value = '';
        showToast('Work domain @' + val + ' added — emails from this domain will be classified as Work', 'success');
    } else {
        const input = document.getElementById('qs-family-email');
        const val = (input.value || '').trim();
        if (!val) { showToast('Enter a family email', 'error'); return; }
        await apiFetch(API + '/api/email/quick-setup', {
            method: 'POST',
            headers: {'Content-Type': 'application/json'},
            body: JSON.stringify({family_email: val}),
        });
        input.value = '';
        showToast(val + ' added as family — their emails will be top priority', 'success');
    }
    loadQuickSetup();
}

async function addQuickSetupItem(type) {
    const val = prompt(type === 'work' ? 'Enter work domain (e.g., mycompany.com):' : 'Enter family email:');
    if (!val) return;
    const key = type === 'work' ? 'work_domain' : 'family_email';
    await apiFetch(API + '/api/email/quick-setup', {
        method: 'POST',
        headers: {'Content-Type': 'application/json'},
        body: JSON.stringify({[key]: val}),
    });
    showToast('Added!', 'success');
    loadQuickSetup();
}

async function removeQuickSetup(type, val) {
    const key = type === 'work' ? 'remove_work_domain' : 'remove_family_email';
    await apiFetch(API + '/api/email/quick-setup', {
        method: 'POST',
        headers: {'Content-Type': 'application/json'},
        body: JSON.stringify({[key]: val}),
    });
    loadQuickSetup();
}

// ── Connected Accounts Management ─────────────────────────────

async function loadAccounts() {
    const container = document.getElementById('accounts-content');
    if (!container) return;

    try {
        const res = await apiFetch(API + '/api/accounts');
        const data = await res.json();
        const emails = data.email || [];
        const calendars = data.calendar || [];
        const oauth = data.google_oauth || [];

        // Fetch health status in parallel
        let health = {};
        try {
            const hRes = await apiFetch(API + '/api/accounts/health');
            health = await hRes.json();
        } catch(e) {}

        let html = '';

        const providerIcons = {
            gmail: 'fab fa-google', outlook: 'fab fa-microsoft',
            yahoo: 'fab fa-yahoo', proton: 'fas fa-shield-alt',
            stalwart: 'fas fa-server', custom: 'fas fa-envelope',
            google: 'fab fa-google', caldav: 'fas fa-calendar-alt',
        };

        function healthDot(id) {
            const h = health[id];
            if (!h) return '';
            const color = h.ok ? 'var(--success,#2ecc71)' : 'var(--error,#e74c3c)';
            return '<span style="width:8px;height:8px;border-radius:50%;background:' + color + ';flex-shrink:0" title="' + escapeHtml(h.message || '') + '"></span>';
        }

        // Email accounts
        if (emails.length) {
            emails.forEach(a => {
                const icon = providerIcons[a.provider] || 'fas fa-envelope';
                const primary = a.is_primary ? ' <span style="font-size:0.65rem;padding:1px 5px;background:var(--accent);color:#fff;border-radius:3px">Primary</span>' : '';
                const label = a.label ? ' <span style="font-size:0.75rem;color:var(--text-dim)">(' + escapeHtml(a.label) + ')</span>' : '';

                html += '<div style="display:flex;align-items:center;gap:10px;padding:8px 0;border-bottom:1px solid var(--border,rgba(255,255,255,0.05))">';
                html += healthDot(a.id);
                html += '<i class="' + icon + '" style="font-size:1.2rem;width:24px;text-align:center;color:var(--accent)"></i>';
                html += '<div style="flex:1;min-width:0">';
                html += '<div style="font-weight:500;font-size:0.9rem">' + escapeHtml(a.address) + primary + label + '</div>';
                html += '<div style="font-size:0.75rem;color:var(--text-dim)">' + escapeHtml(a.provider) + ' &bull; Email</div>';
                html += '</div>';
                html += '<select style="font-size:0.72rem;padding:2px 4px" onchange="setAccountLabel(\'' + a.id + '\',this.value)">';
                ['', 'Personal', 'Work', 'Nonprofit', 'Other'].forEach(l => {
                    html += '<option value="' + l + '"' + (a.label === l ? ' selected' : '') + '>' + (l || 'No label') + '</option>';
                });
                html += '</select>';
                if (!a.is_primary) html += '<button class="browse-item-action" onclick="setAccountPrimary(\'' + a.id + '\')" title="Set as primary"><i class="fas fa-star"></i></button>';
                html += '<button class="browse-item-action danger" onclick="removeAccount(\'' + a.id + '\',\'' + escapeHtml(a.address) + '\')" title="Disconnect"><i class="fas fa-unlink"></i></button>';
                html += '</div>';
            });
        }

        // Calendar accounts
        if (calendars.length) {
            calendars.forEach(a => {
                const icon = providerIcons[a.type] || 'fas fa-calendar';
                const name = a.email || a.url || 'Calendar';
                html += '<div style="display:flex;align-items:center;gap:10px;padding:8px 0;border-bottom:1px solid var(--border,rgba(255,255,255,0.05))">';
                html += '<i class="' + icon + '" style="font-size:1.2rem;width:24px;text-align:center;color:var(--accent)"></i>';
                html += '<div style="flex:1">';
                html += '<div style="font-weight:500;font-size:0.9rem">' + escapeHtml(name) + '</div>';
                html += '<div style="font-size:0.75rem;color:var(--text-dim)">' + escapeHtml(a.type) + ' &bull; Calendar</div>';
                html += '</div>';
                if (a.id) html += '<button class="browse-item-action danger" onclick="removeCalendarAccount(\'' + a.id + '\',\'' + escapeHtml(name) + '\')" title="Disconnect"><i class="fas fa-unlink"></i></button>';
                html += '</div>';
            });
        }

        // Google accounts (multi-account registry)
        const googleAccounts = data.google_accounts || [];
        if (googleAccounts.length) {
            const svcLabels = {gmail: 'Gmail', calendar: 'Calendar', drive: 'Drive', contacts: 'Contacts'};
            googleAccounts.forEach(ga => {
                const services = (ga.services || []).map(s => svcLabels[s] || s).join(', ');
                html += '<div style="display:flex;align-items:center;gap:10px;padding:8px 0;border-bottom:1px solid var(--border,rgba(255,255,255,0.05))">';
                html += '<i class="fab fa-google" style="font-size:1.2rem;width:24px;text-align:center;color:var(--accent)"></i>';
                html += '<div style="flex:1;min-width:0">';
                html += '<div style="font-weight:500;font-size:0.9rem">' + escapeHtml(ga.email) + '</div>';
                html += '<div style="font-size:0.75rem;color:var(--text-dim)">' + escapeHtml(services) + '</div>';
                html += '</div>';
                // Per-service actions
                (ga.services || []).forEach(svc => {
                    const key = 'google_' + svc;
                    const h = health[key];
                    if (h && !h.ok) html += '<button class="browse-item-action" onclick="startGoogleOAuth(\'' + svc + '\')" title="Reconnect ' + svc + '"><i class="fas fa-sync"></i></button>';
                });
                html += '</div>';
            });
        } else if (oauth.length) {
            // Fallback: show legacy individual tokens if no accounts registry yet
            const svcLabels = {gmail: 'Gmail', calendar: 'Calendar', drive: 'Drive', contacts: 'Contacts'};
            oauth.forEach(t => {
                const svc = t.service;
                const key = 'google_' + svc;
                const h = health[key];
                const statusText = h ? h.message : '';
                const statusColor = h ? (h.ok ? 'var(--success,#2ecc71)' : 'var(--error,#e74c3c)') : 'var(--text-dim)';

                html += '<div style="display:flex;align-items:center;gap:10px;padding:8px 0;border-bottom:1px solid var(--border,rgba(255,255,255,0.05))">';
                if (h) html += '<span style="width:8px;height:8px;border-radius:50%;background:' + statusColor + ';flex-shrink:0" title="' + escapeHtml(statusText) + '"></span>';
                html += '<i class="fab fa-google" style="font-size:1.2rem;width:24px;text-align:center;color:var(--accent)"></i>';
                html += '<div style="flex:1">';
                html += '<div style="font-weight:500;font-size:0.9rem">Google ' + (svcLabels[svc] || svc) + '</div>';
                if (statusText) html += '<div style="font-size:0.72rem;color:' + statusColor + '">' + escapeHtml(statusText) + '</div>';
                html += '</div>';
                if (h && !h.ok) html += '<button class="browse-item-action" onclick="startGoogleOAuth(\'' + svc + '\')" title="Reconnect"><i class="fas fa-sync"></i></button>';
                html += '<button class="browse-item-action danger" onclick="revokeGoogleService(\'' + svc + '\')" title="Revoke"><i class="fas fa-unlink"></i></button>';
                html += '</div>';
            });
        }

        if (!emails.length && !calendars.length && !oauth.length) {
            html += '<div style="text-align:center;padding:24px">';
            html += '<i class="fas fa-plug" style="font-size:2em;opacity:0.3;display:block;margin-bottom:12px"></i>';
            html += '<p style="color:var(--text-dim);font-size:0.85rem;margin:0 0 12px">No accounts connected yet.</p>';
            html += '<button class="btn btn-primary" onclick="switchPanel(\'connect\')"><i class="fas fa-plug"></i> Set Up Services</button>';
            html += '</div>';
        }

        // Add account buttons
        html += '<div style="margin-top:12px;display:flex;gap:8px;flex-wrap:wrap">';
        html += '<button class="btn btn-primary" style="font-size:0.82rem" onclick="showAddAccountForm()"><i class="fas fa-plus"></i> Add Email Account</button>';
        if (!oauth.length && !googleAccounts.length) {
            html += '<button class="btn btn-secondary" style="font-size:0.82rem" onclick="startGoogleOAuth(\'gmail\')"><i class="fab fa-google"></i> Connect Google</button>';
        } else {
            html += '<button class="btn btn-secondary" style="font-size:0.82rem" onclick="startGoogleOAuth(\'gmail\')"><i class="fab fa-google"></i> Add Google Account</button>';
        }
        html += '<button class="btn btn-secondary" style="font-size:0.82rem" onclick="showAddCalDavForm()"><i class="fas fa-calendar-plus"></i> Add Calendar</button>';
        html += '<button class="btn btn-secondary" style="font-size:0.82rem" onclick="switchPanel(\'connect\')"><i class="fas fa-plug"></i> More Services</button>';
        html += '</div>';

        // Add account form (hidden)
        html += '<div id="add-account-form" style="display:none;margin-top:12px;background:var(--bg-input);border-radius:8px;padding:14px">';
        html += '<div style="font-weight:600;margin-bottom:8px">Add Email Account</div>';
        html += '<div style="display:flex;gap:6px;margin-bottom:6px">';
        html += '<select id="aa-provider" style="min-width:120px;font-size:0.85rem" onchange="updateAddAccountForm()">';
        html += '<option value="gmail">Gmail (IMAP)</option><option value="outlook">Outlook</option><option value="yahoo">Yahoo</option>';
        html += '<option value="proton">Proton Mail</option><option value="stalwart">Self-Hosted</option><option value="custom">Custom IMAP</option>';
        html += '</select>';
        html += '<input type="email" id="aa-address" placeholder="you@example.com" style="flex:1;font-size:0.85rem">';
        html += '</div>';
        html += '<div id="aa-fields">';
        html += '<input type="password" id="aa-password" placeholder="App password" style="width:100%;font-size:0.85rem;margin-bottom:6px">';
        html += '<div id="aa-server-fields" style="display:none">';
        html += '<div style="display:flex;gap:6px;margin-bottom:6px">';
        html += '<input type="text" id="aa-imap" placeholder="IMAP server" style="flex:1;font-size:0.85rem">';
        html += '<input type="number" id="aa-imap-port" placeholder="993" value="993" style="width:70px;font-size:0.85rem">';
        html += '</div>';
        html += '<div style="display:flex;gap:6px;margin-bottom:6px">';
        html += '<input type="text" id="aa-smtp" placeholder="SMTP server" style="flex:1;font-size:0.85rem">';
        html += '<input type="number" id="aa-smtp-port" placeholder="587" value="587" style="width:70px;font-size:0.85rem">';
        html += '</div></div></div>';
        html += '<div style="display:flex;gap:6px;justify-content:flex-end;margin-top:8px">';
        html += '<span id="aa-test-result" style="flex:1;font-size:0.8rem;align-self:center"></span>';
        html += '<button class="btn btn-secondary" onclick="testAccountConnection()"><i class="fas fa-plug"></i> Test</button>';
        html += '<button class="btn btn-secondary" onclick="document.getElementById(\'add-account-form\').style.display=\'none\'">Cancel</button>';
        html += '<button class="btn btn-primary" onclick="saveNewAccount()"><i class="fas fa-check"></i> Add</button>';
        html += '</div></div>';

        container.innerHTML = html;
    } catch(e) {
        container.innerHTML = '<p style="color:var(--error)">Failed to load accounts: ' + escapeHtml(e.message) + '</p>';
    }
}

function showAddAccountForm() {
    const form = document.getElementById('add-account-form');
    if (form) { form.style.display = ''; updateAddAccountForm(); }
}

function updateAddAccountForm() {
    const provider = document.getElementById('aa-provider').value;
    const serverFields = document.getElementById('aa-server-fields');
    const defaults = {
        gmail: {imap: 'imap.gmail.com', smtp: 'smtp.gmail.com', iport: 993, sport: 587, showServer: false},
        outlook: {imap: 'outlook.office365.com', smtp: 'smtp.office365.com', iport: 993, sport: 587, showServer: false},
        yahoo: {imap: 'imap.mail.yahoo.com', smtp: 'smtp.mail.yahoo.com', iport: 993, sport: 587, showServer: false},
        proton: {imap: '127.0.0.1', smtp: '127.0.0.1', iport: 1143, sport: 1025, showServer: false},
        stalwart: {imap: 'localhost', smtp: 'localhost', iport: 9930, sport: 5870, showServer: false},
        custom: {imap: '', smtp: '', iport: 993, sport: 587, showServer: true},
    };
    const d = defaults[provider] || defaults.custom;
    document.getElementById('aa-imap').value = d.imap;
    document.getElementById('aa-smtp').value = d.smtp;
    document.getElementById('aa-imap-port').value = d.iport;
    document.getElementById('aa-smtp-port').value = d.sport;
    serverFields.style.display = d.showServer ? '' : 'none';
    document.getElementById('aa-test-result').textContent = '';
}

async function testAccountConnection() {
    const result = document.getElementById('aa-test-result');
    const provider = document.getElementById('aa-provider').value;
    const defaults = {
        gmail: {imap: 'imap.gmail.com'}, outlook: {imap: 'outlook.office365.com'},
        yahoo: {imap: 'imap.mail.yahoo.com'}, proton: {imap: '127.0.0.1'},
        stalwart: {imap: 'localhost'}, custom: {imap: ''},
    };
    const imap = document.getElementById('aa-imap').value || (defaults[provider] || {}).imap || '';
    result.innerHTML = '<i class="fas fa-spinner fa-spin"></i> Testing...';
    try {
        const r = await apiFetch(API + '/api/accounts/test', {
            method: 'POST',
            headers: {'Content-Type': 'application/json'},
            body: JSON.stringify({
                imap_server: imap,
                imap_port: parseInt(document.getElementById('aa-imap-port').value || '993'),
                address: document.getElementById('aa-address').value,
                password: document.getElementById('aa-password').value,
            }),
        });
        const d = await r.json();
        result.innerHTML = d.ok
            ? '<span style="color:var(--success)"><i class="fas fa-check-circle"></i> ' + escapeHtml(d.message) + '</span>'
            : '<span style="color:var(--error)"><i class="fas fa-times-circle"></i> ' + escapeHtml(d.error) + '</span>';
    } catch(e) {
        result.innerHTML = '<span style="color:var(--error)">Test failed: ' + escapeHtml(e.message) + '</span>';
    }
}

async function saveNewAccount() {
    const provider = document.getElementById('aa-provider').value;
    const address = document.getElementById('aa-address').value.trim();
    const password = document.getElementById('aa-password').value;
    if (!address) { showToast('Enter email address', 'error'); return; }

    const defaults = {
        gmail: {imap: 'imap.gmail.com', smtp: 'smtp.gmail.com'},
        outlook: {imap: 'outlook.office365.com', smtp: 'smtp.office365.com'},
        yahoo: {imap: 'imap.mail.yahoo.com', smtp: 'smtp.mail.yahoo.com'},
        proton: {imap: '127.0.0.1', smtp: '127.0.0.1'},
        stalwart: {imap: 'localhost', smtp: 'localhost'},
    };
    const d = defaults[provider] || {};

    try {
        await apiFetch(API + '/api/accounts/email', {
            method: 'POST',
            headers: {'Content-Type': 'application/json'},
            body: JSON.stringify({
                address, password, provider,
                imap_server: document.getElementById('aa-imap').value || d.imap || '',
                smtp_server: document.getElementById('aa-smtp').value || d.smtp || '',
                imap_port: parseInt(document.getElementById('aa-imap-port').value || '993'),
                smtp_port: parseInt(document.getElementById('aa-smtp-port').value || '587'),
            }),
        });
        showToast(address + ' added!', 'success');
        document.getElementById('add-account-form').style.display = 'none';
        loadAccounts();
    } catch(e) { showToast('Failed: ' + e.message, 'error'); }
}

async function setAccountLabel(id, label) {
    try {
        await apiFetch(API + '/api/accounts/email/' + id + '/label', {
            method: 'PUT', headers: {'Content-Type': 'application/json'},
            body: JSON.stringify({label}),
        });
    } catch(e) { showToast('Failed: ' + e.message, 'error'); }
}

async function setAccountPrimary(id) {
    try {
        await apiFetch(API + '/api/accounts/email/' + id + '/primary', {method: 'POST'});
        showToast('Primary account updated', 'success');
        loadAccounts();
    } catch(e) { showToast('Failed: ' + e.message, 'error'); }
}

async function removeAccount(id, address) {
    if (!confirm('Disconnect ' + address + '? This removes the account from Familiar but does not delete any emails.')) return;
    try {
        await apiFetch(API + '/api/accounts/email/' + id, {method: 'DELETE'});
        showToast(address + ' disconnected', 'success');
        loadAccounts();
    } catch(e) { showToast('Failed: ' + e.message, 'error'); }
}

async function removeCalendarAccount(id, name) {
    if (!confirm('Disconnect calendar "' + name + '"?')) return;
    try {
        await apiFetch(API + '/api/accounts/calendar/' + id, {method: 'DELETE'});
        showToast(name + ' disconnected', 'success');
        loadAccounts();
    } catch(e) { showToast('Failed: ' + e.message, 'error'); }
}

async function revokeGoogleService(service) {
    const labels = {gmail: 'Gmail', calendar: 'Calendar', drive: 'Drive', contacts: 'Contacts'};
    const name = labels[service] || service;
    if (!confirm('Revoke Google ' + name + '? This removes the OAuth token. You can reconnect later.')) return;
    try {
        await apiFetch(API + '/api/accounts/google/revoke', {
            method: 'POST',
            headers: {'Content-Type': 'application/json'},
            body: JSON.stringify({service}),
        });
        showToast('Google ' + name + ' revoked', 'success');
        loadAccounts();
    } catch(e) { showToast('Failed: ' + e.message, 'error'); }
}

// ── Add CalDAV Calendar ─────────────────────────────

function showAddCalDavForm() {
    const container = document.getElementById('accounts-content');
    let form = document.getElementById('add-caldav-form');
    if (form) { form.style.display = form.style.display === 'none' ? '' : 'none'; return; }

    form = document.createElement('div');
    form.id = 'add-caldav-form';
    form.style.cssText = 'margin-top:12px;background:var(--bg-input);border-radius:8px;padding:14px';
    form.innerHTML = '<div style="font-weight:600;margin-bottom:8px">Add CalDAV Calendar</div>'
        + '<p style="font-size:0.8rem;color:var(--text-dim);margin:0 0 8px">Connect a Nextcloud, Radicale, or any CalDAV calendar.</p>'
        + '<input type="url" id="cd-url" placeholder="CalDAV URL (e.g., https://cloud.example.org/dav/)" style="width:100%;font-size:0.85rem;margin-bottom:6px">'
        + '<div style="display:flex;gap:6px;margin-bottom:6px">'
        + '<input type="text" id="cd-user" placeholder="Username" style="flex:1;font-size:0.85rem">'
        + '<input type="password" id="cd-pass" placeholder="Password" style="flex:1;font-size:0.85rem">'
        + '</div>'
        + '<div style="display:flex;gap:6px;margin-bottom:6px">'
        + '<input type="text" id="cd-label" placeholder="Label (e.g., Nextcloud)" style="flex:1;font-size:0.85rem">'
        + '</div>'
        + '<div style="display:flex;gap:6px;justify-content:flex-end">'
        + '<span id="cd-test-result" style="flex:1;font-size:0.8rem;align-self:center"></span>'
        + '<button class="btn btn-secondary" onclick="testCalDav()"><i class="fas fa-plug"></i> Test</button>'
        + '<button class="btn btn-secondary" onclick="this.closest(\'#add-caldav-form\').style.display=\'none\'">Cancel</button>'
        + '<button class="btn btn-primary" onclick="saveCalDav()"><i class="fas fa-check"></i> Add</button>'
        + '</div>';
    container.appendChild(form);
}

async function testCalDav() {
    const result = document.getElementById('cd-test-result');
    result.innerHTML = '<i class="fas fa-spinner fa-spin"></i> Testing...';
    try {
        const r = await apiFetch(API + '/api/accounts/caldav/test', {
            method: 'POST',
            headers: {'Content-Type': 'application/json'},
            body: JSON.stringify({
                url: document.getElementById('cd-url').value,
                user: document.getElementById('cd-user').value,
                password: document.getElementById('cd-pass').value,
            }),
        });
        const d = await r.json();
        result.innerHTML = d.ok
            ? '<span style="color:var(--success)"><i class="fas fa-check-circle"></i> ' + escapeHtml(d.message || 'Connected') + '</span>'
            : '<span style="color:var(--error)"><i class="fas fa-times-circle"></i> ' + escapeHtml(d.error) + '</span>';
    } catch(e) {
        result.innerHTML = '<span style="color:var(--error)">Test failed</span>';
    }
}

async function saveCalDav() {
    const url = document.getElementById('cd-url').value.trim();
    const user = document.getElementById('cd-user').value.trim();
    const password = document.getElementById('cd-pass').value;
    const label = document.getElementById('cd-label').value.trim();
    if (!url) { showToast('Enter CalDAV URL', 'error'); return; }
    try {
        await apiFetch(API + '/api/accounts/caldav', {
            method: 'POST',
            headers: {'Content-Type': 'application/json'},
            body: JSON.stringify({url, user, password, label}),
        });
        showToast('Calendar added!', 'success');
        document.getElementById('add-caldav-form').style.display = 'none';
        loadAccounts();
    } catch(e) { showToast('Failed: ' + e.message, 'error'); }
}

// ── New UI Toggle ─────────────────────────────────────
function switchToNewUI() {
    if (!confirm('Switch to the new Svelte UI? You can switch back anytime from Settings.')) return;
    fetch('/ui-preference', {
        method: 'POST',
        headers: {'Content-Type': 'application/json'},
        body: JSON.stringify({ui: 'v2'}),
    }).then(() => {
        window.location.href = '/v2/';
    }).catch(() => {
        window.location.href = '/v2/';
    });
}
