(function () {
    window.AgentFrontendModules = window.AgentFrontendModules || {};

    window.AgentFrontendModules.createSettingsPanelModule = function createSettingsPanelModule(deps) {
        function getSettings() {
            return deps.getAppSettings();
        }

        const MODEL_API_KEY_UI = {
            ollama_cloud: {
                label: 'Ollama Cloud',
                inputRef: 'ollamaCloudApiKeyInput',
                buttonRef: 'ollamaCloudApiKeyTestBtn',
                statusRef: 'ollamaCloudApiKeyTestStatus',
            },
            openai: {
                label: 'OpenAI',
                inputRef: 'openaiApiKeyInput',
                buttonRef: 'openaiApiKeyTestBtn',
                statusRef: 'openaiApiKeyTestStatus',
            },
            gemini: {
                label: 'Gemini',
                inputRef: 'geminiApiKeyInput',
                buttonRef: 'geminiApiKeyTestBtn',
                statusRef: 'geminiApiKeyTestStatus',
            },
            nvidia: {
                label: 'NVIDIA',
                inputRef: 'nvidiaApiKeyInput',
                buttonRef: 'nvidiaApiKeyTestBtn',
                statusRef: 'nvidiaApiKeyTestStatus',
            },
        };

        function getModelApiKeyUi(provider) {
            const spec = MODEL_API_KEY_UI[provider];
            if (!spec) return null;
            return {
                label: spec.label,
                input: deps.refs[spec.inputRef] || null,
                button: deps.refs[spec.buttonRef] || null,
                status: deps.refs[spec.statusRef] || null,
            };
        }

        function setModelApiKeyStatus(provider, message, tone, isBusy) {
            const ui = getModelApiKeyUi(provider);
            if (!ui) return;
            const statusEl = ui.status;
            const buttonEl = ui.button;
            if (statusEl) {
                statusEl.textContent = message || '';
                statusEl.className = 'settings-note' + (tone === 'ok' ? ' ok' : tone === 'err' ? ' err' : '');
            }
            if (buttonEl) {
                if (!buttonEl.dataset.defaultLabel) buttonEl.dataset.defaultLabel = buttonEl.textContent || 'Test';
                buttonEl.disabled = !!isBusy;
                buttonEl.textContent = isBusy ? 'Testing…' : buttonEl.dataset.defaultLabel;
            }
        }

        function clearModelApiKeyStatuses() {
            Object.keys(MODEL_API_KEY_UI).forEach((provider) => setModelApiKeyStatus(provider, '', '', false));
        }

        function setRunEmailToggleState(outlookAvailable, outlookEnabled) {
            const emailEnabledThisRun = !!outlookAvailable && !!outlookEnabled;
            if (deps.refs.emailToggle) {
                deps.refs.emailToggle.disabled = !emailEnabledThisRun;
                if (!emailEnabledThisRun) deps.refs.emailToggle.checked = false;
                else deps.refs.emailToggle.checked = true;
            }
            if (deps.refs.emailAccessHint) {
                const message = !outlookAvailable
                    ? 'Outlook unavailable: install pywin32 and restart backend.'
                    : (outlookEnabled ? '' : 'Enable Outlook in Settings first (gear icon).');
                deps.refs.emailAccessHint.textContent = message;
                deps.refs.emailAccessHint.style.display = message ? '' : 'none';
            }
        }

        function resetUiFromSettings() {
            const appSettings = getSettings();
            if (deps.refs.settingsOverlay) deps.refs.settingsOverlay.style.display = 'none';
            deps.helpers.applyCopilotUiFromSettings();
            clearModelApiKeyStatuses();

            if (deps.refs.nvidiaApiKeyInput) deps.refs.nvidiaApiKeyInput.value = appSettings.nvidia_api_key || '';
            if (deps.refs.braveApiKeyInput) deps.refs.braveApiKeyInput.value = appSettings.brave_api_key || '';
            if (deps.refs.ollamaCloudApiKeyInput) deps.refs.ollamaCloudApiKeyInput.value = appSettings.ollama_cloud_api_key || '';
            if (deps.refs.openaiApiKeyInput) deps.refs.openaiApiKeyInput.value = appSettings.openai_api_key || '';
            if (deps.refs.geminiApiKeyInput) deps.refs.geminiApiKeyInput.value = appSettings.gemini_api_key || '';
            if (deps.refs.llamacppUrlInput) deps.refs.llamacppUrlInput.value = appSettings.llamacpp_url || 'http://localhost:8080';
            if (deps.refs.llamacppModelPathInput) deps.refs.llamacppModelPathInput.value = appSettings.llamacpp_model_path || '';
            if (deps.refs.llamacppExtraArgsInput) deps.refs.llamacppExtraArgsInput.value = appSettings.llamacpp_extra_args || '';
            if (deps.refs.outlookToggle) deps.refs.outlookToggle.checked = !!appSettings.outlook_enabled;
            if (deps.refs.googleToggle) deps.refs.googleToggle.checked = !!appSettings.google_enabled;
            if (deps.refs.googleClientId) deps.refs.googleClientId.value = appSettings.google_client_id || '';
            if (deps.refs.googleClientSecret) deps.refs.googleClientSecret.value = appSettings.google_client_secret || '';
            if (deps.refs.microsoftToggle) deps.refs.microsoftToggle.checked = !!appSettings.microsoft_enabled;
            if (deps.refs.microsoftClientId) deps.refs.microsoftClientId.value = appSettings.microsoft_client_id || '';
            if (deps.refs.microsoftClientSecret) deps.refs.microsoftClientSecret.value = appSettings.microsoft_client_secret || '';
            if (deps.refs.slackToggle) deps.refs.slackToggle.checked = !!appSettings.slack_enabled;
            if (deps.refs.slackBotToken) deps.refs.slackBotToken.value = appSettings.slack_bot_token || '';
            if (deps.refs.slackAppToken) deps.refs.slackAppToken.value = appSettings.slack_app_token || '';
            if (deps.refs.slackWebhookUrl) deps.refs.slackWebhookUrl.value = appSettings.slack_webhook_url || '';
            if (deps.refs.telegramToggle) deps.refs.telegramToggle.checked = !!appSettings.telegram_enabled;
            if (deps.refs.telegramBotToken) deps.refs.telegramBotToken.value = appSettings.telegram_bot_token || '';
            if (deps.refs.whatsappToggle) deps.refs.whatsappToggle.checked = !!appSettings.whatsapp_enabled;
            appSettings.policy_budget_mode = deps.helpers.normalizePolicyBudgetMode(appSettings.policy_budget_mode);
            if (deps.refs.policyBudgetModeSelect) deps.refs.policyBudgetModeSelect.value = appSettings.policy_budget_mode;
            if (deps.refs.policyMaxStepsInput) deps.refs.policyMaxStepsInput.value = appSettings.policy_max_steps_per_run ?? 8;
            if (deps.refs.policyMaxToolCallsInput) deps.refs.policyMaxToolCallsInput.value = appSettings.policy_max_tool_calls_per_run ?? 20;
            if (deps.refs.policyMaxRetriesInput) deps.refs.policyMaxRetriesInput.value = appSettings.policy_max_validation_retries_per_step ?? 1;
            if (deps.refs.policyMaxTokensInput) deps.refs.policyMaxTokensInput.value = appSettings.policy_max_total_tokens_per_run ?? 120000;
            if (deps.refs.policyMaxRuntimeInput) deps.refs.policyMaxRuntimeInput.value = appSettings.policy_max_runtime_seconds ?? 900;
            if (deps.refs.policyBlockedToolsInput) deps.refs.policyBlockedToolsInput.value = deps.helpers.toolsToCsv(appSettings.policy_blocked_tools);
            if (deps.refs.policyApprovalToolsInput) deps.refs.policyApprovalToolsInput.value = deps.helpers.toolsToCsv(appSettings.policy_require_approval_tools);
            deps.helpers.updatePolicyBudgetModeUi();
            if (deps.refs.browserHeadlessToggle) deps.refs.browserHeadlessToggle.checked = true;
            if (deps.refs.showThinkingToggle) deps.refs.showThinkingToggle.checked = !!appSettings.show_thinking;
            if (deps.refs.mcpServersInput) {
                deps.refs.mcpServersInput.value = typeof appSettings.mcp_servers === 'object' && appSettings.mcp_servers
                    ? JSON.stringify(appSettings.mcp_servers, null, 2)
                    : '{}';
            }
            deps.helpers.whRenderList(appSettings.webhooks || []);
            deps.helpers.applyModelSettingsToUi();
            deps.helpers.refreshProviderNotes();
        }

        async function loadSettings() {
            try {
                deps.setIsLoadingSettings(true);
                clearModelApiKeyStatuses();
                const responses = await Promise.all([
                    deps.authFetch('/api/capabilities'),
                    deps.authFetch('/api/settings'),
                ]);
                const capsRes = responses[0];
                const settingsRes = responses[1];
                if (!settingsRes.ok) {
                    console.warn('loadSettings: failed to fetch settings', settingsRes.status);
                    return;
                }

                const caps = await capsRes.json();
                const settings = await settingsRes.json();
                if (settings.detail) {
                    console.warn('loadSettings: got error response, skipping', settings);
                    return;
                }

                deps.setRuntimeCapabilities(caps || {});
                deps.setAppSettings(deps.helpers.normalizeCopilotSettings(settings));
                const appSettings = getSettings();

                deps.helpers.applyCopilotUiFromSettings();
                deps.helpers.loadManagedContextSources(settings);
                if (deps.refs.nvidiaApiKeyInput) deps.refs.nvidiaApiKeyInput.value = settings.nvidia_api_key || '';
                if (deps.refs.braveApiKeyInput) deps.refs.braveApiKeyInput.value = settings.brave_api_key || '';
                if (deps.refs.ollamaCloudApiKeyInput) deps.refs.ollamaCloudApiKeyInput.value = settings.ollama_cloud_api_key || '';
                if (deps.refs.openaiApiKeyInput) deps.refs.openaiApiKeyInput.value = settings.openai_api_key || '';
                if (deps.refs.geminiApiKeyInput) deps.refs.geminiApiKeyInput.value = settings.gemini_api_key || '';
                if (deps.refs.llamacppUrlInput) deps.refs.llamacppUrlInput.value = settings.llamacpp_url || 'http://localhost:8080';
                if (deps.refs.llamacppModelPathInput) deps.refs.llamacppModelPathInput.value = settings.llamacpp_model_path || '';
                if (deps.refs.llamacppExtraArgsInput) deps.refs.llamacppExtraArgsInput.value = settings.llamacpp_extra_args || '';
                if (deps.refs.outlookToggle) deps.refs.outlookToggle.checked = !!settings.outlook_enabled;
                deps.helpers.ftLoadFromSettings(settings);
                deps.helpers.gftLoadFromSettings(settings);
                deps.helpers.syncStructuralContextFromUi(appSettings);
                if (deps.refs.googleToggle) deps.refs.googleToggle.checked = !!settings.google_enabled;
                if (deps.refs.googleClientId) deps.refs.googleClientId.value = settings.google_client_id || '';
                if (deps.refs.googleClientSecret) deps.refs.googleClientSecret.value = settings.google_client_secret || '';

                let googleAuthorized = false;
                let microsoftAuthorized = false;
                deps.authFetchJson('/api/integrations/google/status').then((status) => {
                    googleAuthorized = !!status.authorized;
                    let googleContextMessage = 'Authorize Google in Integrations to browse Gmail labels here.';
                    let googleContextTone = '';
                    if (deps.refs.googleAuthStatus) {
                        if (status.authorized && status.scopes_ok !== false) {
                            deps.refs.googleAuthStatus.textContent = '\u2705 Authorized';
                            deps.refs.googleAuthStatus.className = 'settings-note ok';
                            googleContextMessage = 'Connected. Scan Gmail labels and choose which ones should stay in structural context.';
                            googleContextTone = 'ok';
                        } else if (status.token_file_exists && status.scopes_ok === false) {
                            deps.refs.googleAuthStatus.textContent = '\u26a0\ufe0f Re-authorization needed — new Google permissions were added. Click "Authorize Google" again.';
                            deps.refs.googleAuthStatus.className = 'settings-note err';
                            googleAuthorized = false;
                            googleContextMessage = 'Re-authorize Google in Integrations to browse Gmail labels again.';
                            googleContextTone = 'err';
                        } else if (status.has_credentials) {
                            deps.refs.googleAuthStatus.textContent = 'Not yet authorized — click "Authorize Google" to connect.';
                            deps.refs.googleAuthStatus.className = 'settings-note';
                            googleContextMessage = 'Google is configured but not authorized yet. Authorize it in Integrations to scan labels.';
                        } else {
                            googleContextMessage = 'Enable and authorize Google in Integrations to manage Gmail labels here.';
                        }
                    }
                    deps.helpers.setEmailContextSectionState(deps.refs.googleFolderSection, deps.refs.googleScanBtn, deps.refs.googleContextStatus, {
                        available: googleAuthorized,
                        message: googleContextMessage,
                        tone: googleContextTone,
                    });
                    deps.helpers.cloudUpdateStatus(googleAuthorized, microsoftAuthorized);
                }).catch(() => {});

                if (deps.refs.microsoftToggle) deps.refs.microsoftToggle.checked = !!settings.microsoft_enabled;
                if (deps.refs.microsoftClientId) deps.refs.microsoftClientId.value = settings.microsoft_client_id || '';
                if (deps.refs.microsoftClientSecret) deps.refs.microsoftClientSecret.value = settings.microsoft_client_secret || '';
                const onedriveMode = settings.onedrive_mode || 'local';
                if (deps.refs.onedriveModeLocal) deps.refs.onedriveModeLocal.checked = onedriveMode === 'local';
                if (deps.refs.onedriveModeGraph) deps.refs.onedriveModeGraph.checked = onedriveMode === 'graph';
                if (deps.refs.onedriveLocalPath) deps.refs.onedriveLocalPath.value = settings.onedrive_local_path || '';
                if (deps.refs.onedriveContextHint) {
                    deps.refs.onedriveContextHint.textContent = onedriveMode === 'local'
                        ? 'Local mode uses your synced OneDrive folder. Add the root or choose subfolders below.'
                        : 'Graph mode uses your authorized Microsoft account. Choose folders to keep as persistent context.';
                }
                if (deps.refs.googleDriveContextHint) {
                    deps.refs.googleDriveContextHint.textContent = !!settings.google_enabled
                        ? 'Uses your Google account. Choose folders later or deselect them here.'
                        : 'Google Drive context is managed here after you enable and authorize Google in Integrations.';
                }
                deps.helpers.applyOneDriveMode(onedriveMode);

                deps.authFetchJson('/api/integrations/microsoft/status').then((status) => {
                    microsoftAuthorized = !!status.authorized;
                    const mode = status.onedrive_mode || 'local';
                    const localOk = !!status.onedrive_local_ok;
                    if (deps.refs.microsoftAuthStatus && mode === 'graph') {
                        if (status.authorized) {
                            deps.refs.microsoftAuthStatus.textContent = '\u2705 Authorized';
                            deps.refs.microsoftAuthStatus.className = 'settings-note ok';
                        } else if (status.has_credentials) {
                            deps.refs.microsoftAuthStatus.textContent = 'Not yet authorized — click "Authorize Microsoft" to connect.';
                            deps.refs.microsoftAuthStatus.className = 'settings-note';
                        }
                    }
                    if (deps.refs.onedriveLocalStatus && mode === 'local') {
                        if (localOk) {
                            deps.refs.onedriveLocalStatus.textContent = '\u2705 Folder found — ready to use.';
                            deps.refs.onedriveLocalStatus.className = 'settings-note ok';
                        } else if (deps.refs.onedriveLocalPath && deps.refs.onedriveLocalPath.value) {
                            deps.refs.onedriveLocalStatus.textContent = '\u26a0\ufe0f Folder not found at the specified path.';
                            deps.refs.onedriveLocalStatus.className = 'settings-note';
                        }
                    }
                    const microsoftOk = mode === 'local' ? localOk : microsoftAuthorized;
                    deps.helpers.cloudUpdateStatus(googleAuthorized, microsoftOk);
                }).catch(() => {});

                if (deps.refs.slackToggle) deps.refs.slackToggle.checked = !!settings.slack_enabled;
                if (deps.refs.slackBotToken) deps.refs.slackBotToken.value = settings.slack_bot_token || '';
                if (deps.refs.slackAppToken) deps.refs.slackAppToken.value = settings.slack_app_token || '';
                if (deps.refs.slackWebhookUrl) deps.refs.slackWebhookUrl.value = settings.slack_webhook_url || '';
                if (deps.refs.telegramToggle) deps.refs.telegramToggle.checked = !!settings.telegram_enabled;
                if (deps.refs.telegramBotToken) deps.refs.telegramBotToken.value = settings.telegram_bot_token || '';
                if (deps.refs.whatsappToggle) deps.refs.whatsappToggle.checked = !!settings.whatsapp_enabled;
                deps.helpers.waRefreshStatus();

                appSettings.policy_budget_mode = deps.helpers.normalizePolicyBudgetMode(settings.policy_budget_mode);
                if (deps.refs.policyBudgetModeSelect) deps.refs.policyBudgetModeSelect.value = appSettings.policy_budget_mode;
                if (deps.refs.policyMaxStepsInput) deps.refs.policyMaxStepsInput.value = settings.policy_max_steps_per_run ?? 8;
                if (deps.refs.policyMaxToolCallsInput) deps.refs.policyMaxToolCallsInput.value = settings.policy_max_tool_calls_per_run ?? 20;
                if (deps.refs.policyMaxRetriesInput) deps.refs.policyMaxRetriesInput.value = settings.policy_max_validation_retries_per_step ?? 1;
                if (deps.refs.policyMaxTokensInput) deps.refs.policyMaxTokensInput.value = settings.policy_max_total_tokens_per_run ?? 120000;
                if (deps.refs.policyMaxRuntimeInput) deps.refs.policyMaxRuntimeInput.value = settings.policy_max_runtime_seconds ?? 900;
                if (deps.refs.policyBlockedToolsInput) deps.refs.policyBlockedToolsInput.value = deps.helpers.toolsToCsv(settings.policy_blocked_tools);
                if (deps.refs.policyApprovalToolsInput) deps.refs.policyApprovalToolsInput.value = deps.helpers.toolsToCsv(settings.policy_require_approval_tools);
                deps.helpers.updatePolicyBudgetModeUi();
                if (deps.refs.browserHeadlessToggle) deps.refs.browserHeadlessToggle.checked = true;
                if (deps.refs.showThinkingToggle) deps.refs.showThinkingToggle.checked = !!settings.show_thinking;
                if (deps.refs.mcpServersInput) {
                    deps.refs.mcpServersInput.value = typeof settings.mcp_servers === 'object' && settings.mcp_servers
                        ? JSON.stringify(settings.mcp_servers, null, 2)
                        : '{}';
                }
                deps.helpers.mcpRenderServerList();
                deps.helpers.mcpUpdatePresetChips();
                deps.helpers.mcpFetchStatus();
                appSettings.webhooks = Array.isArray(settings.webhooks) ? settings.webhooks : [];
                deps.helpers.whRenderList(appSettings.webhooks);
                appSettings.tool_enabled_map = settings.tool_enabled_map && typeof settings.tool_enabled_map === 'object'
                    ? { ...settings.tool_enabled_map }
                    : {};

                deps.setOutlookAvailable(!!caps.outlook);
                deps.helpers.setEmailContextSectionState(deps.refs.outlookFolderSection, deps.refs.outlookScanBtn, deps.refs.outlookContextStatus, {
                    available: deps.getOutlookAvailable(),
                    message: deps.getOutlookAvailable()
                        ? 'Available. Scan Outlook folders and choose which ones should stay in structural context.'
                        : 'Outlook is not available yet. Enable Outlook support and restart the backend to scan folders here.',
                    tone: deps.getOutlookAvailable() ? 'ok' : '',
                });
                deps.helpers.applyModelSettingsToUi();
                deps.helpers.refreshProviderNotes(caps);
                setRunEmailToggleState(deps.getOutlookAvailable(), !!settings.outlook_enabled);

                if (deps.refs.outlookBadge) {
                    if (caps.outlook) {
                        deps.refs.outlookBadge.textContent = 'available';
                        deps.refs.outlookBadge.style.background = '#22c55e22';
                        deps.refs.outlookBadge.style.color = '#4ade80';
                    } else {
                        deps.refs.outlookBadge.textContent = 'pywin32 missing';
                        deps.refs.outlookBadge.style.background = 'rgba(239,68,68,.15)';
                        deps.refs.outlookBadge.style.color = 'var(--danger)';
                    }
                }
                if (deps.refs.outlookNote) {
                    deps.refs.outlookNote.textContent = caps.outlook
                        ? 'When enabled, agents can read/send emails and read your calendar.'
                        : 'Install pywin32 to use Outlook skills:  pip install pywin32';
                }
            } catch (error) {
                console.warn('loadSettings:', error);
            } finally {
                deps.setIsLoadingSettings(false);
            }
        }

        async function testModelApiKey(provider) {
            const ui = getModelApiKeyUi(provider);
            if (!ui) return;
            const candidateKey = ui.input ? ui.input.value.trim() : '';
            setModelApiKeyStatus(provider, `Testing ${ui.label} API key…`, '', true);
            try {
                const requestBody = { provider, api_key: candidateKey };
                if (provider === 'ollama_cloud') {
                    requestBody.selected_model = deps.refs.modelSelect ? deps.refs.modelSelect.value : '';
                    requestBody.main_model = deps.refs.modelSelect ? deps.refs.modelSelect.value : '';
                    requestBody.fast_model = deps.refs.fastModelSelect ? deps.refs.fastModelSelect.value : '';
                    requestBody.fallback_model = deps.refs.fallbackModelSelect ? deps.refs.fallbackModelSelect.value : '';
                }
                const response = await deps.authFetch('/api/settings/test-model-api-key', {
                    method: 'POST',
                    headers: { 'Content-Type': 'application/json' },
                    body: JSON.stringify(requestBody),
                });
                const payload = await response.json().catch(() => ({}));
                const message = String(payload.detail || payload.error || `Could not test ${ui.label} API key.`).trim();
                if (!response.ok || payload.ok === false) {
                    setModelApiKeyStatus(provider, message, 'err', false);
                    deps.helpers.showToast('error', message, 5000);
                    return;
                }
                const tone = payload.verified === false ? '' : 'ok';
                setModelApiKeyStatus(provider, message, tone, false);
                deps.helpers.showToast(payload.verified === false ? 'info' : 'success', message, 4000);
            } catch (error) {
                const message = `Could not test ${ui.label} API key: ${error.message || error}`;
                setModelApiKeyStatus(provider, message, 'err', false);
                deps.helpers.showToast('error', message, 5000);
            }
        }

        function bindApiKeyTestButtons() {
            Object.keys(MODEL_API_KEY_UI).forEach((provider) => {
                const ui = getModelApiKeyUi(provider);
                if (!ui?.button || ui.button.dataset.bound === 'true') return;
                ui.button.dataset.bound = 'true';
                ui.button.addEventListener('click', () => {
                    testModelApiKey(provider);
                });
            });
        }

        async function saveSettings() {
            deps.clearPendingContextSave();

            const appSettings = getSettings();
            const copilotState = deps.helpers.collectCopilotStateFromUi();
            appSettings.copilot_enabled = copilotState.copilot_enabled;
            appSettings.copilot_morning_brief_enabled = copilotState.copilot_morning_brief_enabled;
            appSettings.copilot_morning_brief_time = copilotState.copilot_morning_brief_time;
            appSettings.copilot_followup_enabled = copilotState.copilot_followup_enabled;
            appSettings.copilot_followup_time = copilotState.copilot_followup_time;
            appSettings.copilot_briefing_time = copilotState.copilot_briefing_time;
            appSettings.copilot_autonomy_level = copilotState.copilot_autonomy_level;
            appSettings.copilot_morning_brief_instructions = copilotState.copilot_morning_brief_instructions;
            appSettings.copilot_followup_instructions = copilotState.copilot_followup_instructions;
            appSettings.copilot_instructions = copilotState.copilot_instructions;
            appSettings.outlook_enabled = deps.refs.outlookToggle ? deps.refs.outlookToggle.checked : false;
            const ftData = deps.helpers.ftCollect();
            appSettings.outlook_extra_folders = ftData.outlook_extra_folders;
            appSettings.outlook_folder_profiles = ftData.outlook_folder_profiles;
            const gftData = deps.helpers.gftCollect();
            appSettings.google_extra_folders = gftData.google_extra_folders;
            appSettings.google_folder_profiles = gftData.google_folder_profiles;
            appSettings.context_sources = deps.helpers.syncStructuralContextFromUi();
            appSettings.google_enabled = deps.refs.googleToggle ? deps.refs.googleToggle.checked : false;
            appSettings.google_client_id = deps.refs.googleClientId ? deps.refs.googleClientId.value.trim() : '';
            appSettings.google_client_secret = deps.refs.googleClientSecret ? deps.refs.googleClientSecret.value.trim() : '';
            appSettings.microsoft_enabled = deps.refs.microsoftToggle ? deps.refs.microsoftToggle.checked : false;
            appSettings.microsoft_client_id = deps.refs.microsoftClientId ? deps.refs.microsoftClientId.value.trim() : '';
            appSettings.microsoft_client_secret = deps.refs.microsoftClientSecret ? deps.refs.microsoftClientSecret.value.trim() : '';
            appSettings.onedrive_mode = deps.refs.onedriveModeGraph && deps.refs.onedriveModeGraph.checked ? 'graph' : 'local';
            appSettings.onedrive_local_path = deps.refs.onedriveLocalPath ? deps.refs.onedriveLocalPath.value.trim() : '';
            appSettings.slack_enabled = deps.refs.slackToggle ? deps.refs.slackToggle.checked : false;
            appSettings.slack_bot_token = deps.refs.slackBotToken ? deps.refs.slackBotToken.value.trim() : '';
            appSettings.slack_app_token = deps.refs.slackAppToken ? deps.refs.slackAppToken.value.trim() : '';
            appSettings.slack_webhook_url = deps.refs.slackWebhookUrl ? deps.refs.slackWebhookUrl.value.trim() : '';
            appSettings.telegram_enabled = deps.refs.telegramToggle ? deps.refs.telegramToggle.checked : false;
            appSettings.telegram_bot_token = deps.refs.telegramBotToken ? deps.refs.telegramBotToken.value.trim() : '';
            appSettings.whatsapp_enabled = deps.refs.whatsappToggle ? deps.refs.whatsappToggle.checked : false;
            appSettings.main_model = deps.refs.modelSelect ? deps.refs.modelSelect.value : '';
            appSettings.fast_model = deps.refs.fastModelSelect ? deps.refs.fastModelSelect.value : '';
            appSettings.fallback_model = deps.refs.fallbackModelSelect ? deps.refs.fallbackModelSelect.value : '';
            appSettings.nvidia_api_key = deps.refs.nvidiaApiKeyInput ? deps.refs.nvidiaApiKeyInput.value.trim() : '';
            appSettings.brave_api_key = deps.refs.braveApiKeyInput ? deps.refs.braveApiKeyInput.value.trim() : '';
            appSettings.ollama_cloud_api_key = deps.refs.ollamaCloudApiKeyInput ? deps.refs.ollamaCloudApiKeyInput.value.trim() : '';
            appSettings.openai_api_key = deps.refs.openaiApiKeyInput ? deps.refs.openaiApiKeyInput.value.trim() : '';
            appSettings.gemini_api_key = deps.refs.geminiApiKeyInput ? deps.refs.geminiApiKeyInput.value.trim() : '';
            appSettings.llamacpp_url = deps.refs.llamacppUrlInput ? (deps.refs.llamacppUrlInput.value.trim() || 'http://localhost:8080') : 'http://localhost:8080';
            appSettings.llamacpp_model_path = deps.refs.llamacppModelPathInput ? deps.refs.llamacppModelPathInput.value.trim() : '';
            appSettings.llamacpp_extra_args = deps.refs.llamacppExtraArgsInput ? deps.refs.llamacppExtraArgsInput.value.trim() : '';
            appSettings.policy_budget_mode = deps.helpers.normalizePolicyBudgetMode(deps.refs.policyBudgetModeSelect ? deps.refs.policyBudgetModeSelect.value : appSettings.policy_budget_mode);
            appSettings.policy_max_steps_per_run = deps.helpers.asPositiveInt(deps.refs.policyMaxStepsInput ? deps.refs.policyMaxStepsInput.value : 8, 8, 1);
            appSettings.policy_max_tool_calls_per_run = deps.helpers.asPositiveInt(deps.refs.policyMaxToolCallsInput ? deps.refs.policyMaxToolCallsInput.value : 20, 20, 1);
            appSettings.policy_max_validation_retries_per_step = deps.helpers.asPositiveInt(deps.refs.policyMaxRetriesInput ? deps.refs.policyMaxRetriesInput.value : 1, 1, 0);
            appSettings.policy_max_total_tokens_per_run = deps.helpers.asPositiveInt(deps.refs.policyMaxTokensInput ? deps.refs.policyMaxTokensInput.value : 120000, 120000, 1);
            appSettings.policy_max_runtime_seconds = deps.helpers.asPositiveInt(deps.refs.policyMaxRuntimeInput ? deps.refs.policyMaxRuntimeInput.value : 900, 900, 10);
            appSettings.policy_blocked_tools = deps.helpers.csvToTools(deps.refs.policyBlockedToolsInput ? deps.refs.policyBlockedToolsInput.value : '');
            appSettings.policy_require_approval_tools = deps.helpers.csvToTools(deps.refs.policyApprovalToolsInput ? deps.refs.policyApprovalToolsInput.value : '');
            appSettings.browser_headless = true;
            appSettings.show_thinking = deps.refs.showThinkingToggle ? deps.refs.showThinkingToggle.checked : false;

            if (deps.refs.mcpServersInput) {
                try {
                    appSettings.mcp_servers = JSON.parse(deps.refs.mcpServersInput.value || '{}');
                    if (deps.refs.mcpServersNote) deps.refs.mcpServersNote.textContent = '';
                } catch (error) {
                    if (deps.refs.mcpServersNote) {
                        deps.refs.mcpServersNote.textContent = 'Invalid JSON — MCP servers not saved.';
                        deps.refs.mcpServersNote.style.color = 'var(--error)';
                    }
                }
            }

            appSettings.webhooks = deps.helpers.whCollect();
            const selectedModel = String(appSettings.model || '').toLowerCase();
            const keyChecks = [
                ['openai_api_key', /^sk-/, 'OpenAI key should start with "sk-"'],
            ];
            if (selectedModel.includes('gemini')) {
                keyChecks.push(['gemini_api_key', /^AIza/, 'Gemini key should start with "AIza"']);
            }
            for (const item of keyChecks) {
                const field = item[0];
                const regex = item[1];
                const message = item[2];
                const value = appSettings[field];
                if (value && !regex.test(value)) deps.helpers.showToast('warning', message + ' — double-check the value.', 6000);
            }

            try {
                await deps.authFetch('/api/settings', {
                    method: 'POST',
                    headers: { 'Content-Type': 'application/json' },
                    body: JSON.stringify(appSettings),
                });
                const data = await deps.helpers.syncCopilotSchedules();
                const serverSchedules = Array.isArray(data?.schedules) ? data.schedules : Array.isArray(data?.serverSchedules) ? data.serverSchedules : [];
                const localSchedules = Array.isArray(data?.localSchedules) ? data.localSchedules : deps.helpers.loadSchedules();
                deps.helpers.updateCopilotStatusFromSchedules(serverSchedules, localSchedules);
                deps.helpers.renderSchedules();
                await deps.helpers.loadModels();
                setTimeout(deps.helpers.mcpFetchStatus, 3000);
                deps.helpers.showToast('success', 'Settings saved', 2000);
            } catch (error) {
                console.warn('saveSettings:', error);
                deps.helpers.showToast('error', 'Failed to save settings: ' + (error.message || error), 5000);
                deps.helpers.setAllCopilotStatuses('Could not save Co-Pilot: ' + (error.message || error), 'err');
            }

            setRunEmailToggleState(deps.getOutlookAvailable(), !!appSettings.outlook_enabled);
            deps.helpers.applyModelSettingsToUi();
            deps.helpers.refreshProviderNotes();
            if (deps.refs.settingsOverlay) deps.refs.settingsOverlay.style.display = 'none';
        }

        return {
            bindApiKeyTestButtons,
            loadSettings,
            resetUiFromSettings,
            saveSettings,
        };
    };
})();