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

    window.AgentFrontendModules.createModelSettingsModule = function createModelSettingsModule(deps) {
        let currentOllamaInstalledModels = [];
        let ollamaPullPollingId = null;

        function getSettings() {
            return deps.getAppSettings() || {};
        }

        function refreshProviderNotes(caps) {
            const activeCaps = caps || deps.getRuntimeCapabilities() || {};
            const settings = getSettings();

            if (deps.refs.ollamaApiNote) {
                const configured = !!((settings.ollama_cloud_api_key || '').trim()) || !!activeCaps?.ollama_cloud;
                deps.refs.ollamaApiNote.textContent = configured
                    ? 'Ollama Cloud API key configured.'
                    : 'Ollama Cloud API key not set.';
                deps.refs.ollamaApiNote.className = 'settings-note' + (configured ? ' ok' : '');
            }
            if (deps.refs.openaiNote) {
                const configured = !!((settings.openai_api_key || '').trim()) || !!activeCaps?.openai;
                deps.refs.openaiNote.textContent = configured
                    ? 'OpenAI API key configured. GPT / o-series models are available.'
                    : 'OpenAI API key not set. OpenAI models are hidden.';
                deps.refs.openaiNote.className = 'settings-note' + (configured ? ' ok' : '');
            }
            if (deps.refs.geminiNote) {
                const configured = !!((settings.gemini_api_key || '').trim()) || !!activeCaps?.gemini;
                deps.refs.geminiNote.textContent = configured
                    ? 'Gemini API key configured. Gemini models are available.'
                    : 'Gemini API key not set. Gemini models are hidden.';
                deps.refs.geminiNote.className = 'settings-note' + (configured ? ' ok' : '');
            }
            if (deps.refs.nvidiaNote) {
                const configured = !!((settings.nvidia_api_key || '').trim()) || !!activeCaps?.nvidia;
                deps.refs.nvidiaNote.textContent = configured
                    ? 'NVIDIA API key configured. NVIDIA models are available in model lists.'
                    : 'NVIDIA API key not set. NVIDIA models are hidden.';
                deps.refs.nvidiaNote.className = 'settings-note' + (configured ? ' ok' : '');
            }
            const llamacppNote = document.getElementById('llamacpp-note');
            if (llamacppNote) {
                const llamacppOk = !!activeCaps?.llamacpp;
                llamacppNote.textContent = llamacppOk
                    ? 'llama.cpp server is running. Local llama.cpp models are available.'
                    : 'llama.cpp server not running. It starts automatically when you select a llama.cpp model.';
                llamacppNote.className = 'settings-note' + (llamacppOk ? ' ok' : '');
            }
            if (deps.refs.braveNote) {
                const configured = !!((settings.brave_api_key || '').trim()) || !!activeCaps?.brave_search;
                deps.refs.braveNote.textContent = configured
                    ? 'Brave Search API configured. Internet search uses Brave first.'
                    : 'Brave Search API key not set. Fallback search is used.';
                deps.refs.braveNote.className = 'settings-note' + (configured ? ' ok' : '');
            }
            const browserNote = document.getElementById('browser-note');
            if (browserNote) {
                const browserOk = !!activeCaps?.browser;
                const browserPackageInstalled = !!activeCaps?.browser_package_installed;
                const browserDetail = String(activeCaps?.browser_detail || '').trim();
                browserNote.textContent = browserOk
                    ? 'Playwright and Chromium installed — browser skills are available.'
                    : (browserDetail || (browserPackageInstalled
                        ? 'Playwright installed, but Chromium is missing. Run: python -m playwright install chromium'
                        : 'Playwright not found. Run: pip install playwright && python -m playwright install chromium'));
                browserNote.className = 'settings-note' + (browserOk ? ' ok' : '');
            }
            if (deps.refs.browserSupportBadge) {
                const browserOk = !!activeCaps?.browser;
                const browserPackageInstalled = !!activeCaps?.browser_package_installed;
                deps.refs.browserSupportBadge.textContent = browserOk ? '✓ Ready' : (browserPackageInstalled ? 'Chromium missing' : 'Not installed');
                deps.refs.browserSupportBadge.className = 'badge' + (browserOk ? ' badge-ok' : ' badge-warn');
            }
        }

        function updateModelLabel() {
            if (!deps.refs.modelLabelEl) return;
            const settings = getSettings();
            const modelId = settings.main_model || '';
            const display = modelId.replace(/^(nvidia\/|openai\/|gemini\/|ollama\/|llamacpp\/)/, '');
            deps.refs.modelLabelEl.textContent = display || '';
            deps.refs.modelLabelEl.title = modelId ? `Model: ${modelId}` : 'No model selected';
        }

        function ensureRecommendedModelOptions() {
            const recommendedValues = [
                deps.recommendedOllamaProfile.main,
                deps.recommendedOllamaProfile.fast,
                deps.recommendedOllamaProfile.fallback,
            ];
            const labels = {
                [deps.recommendedOllamaProfile.main]: 'glm-5.1:cloud  [Recommended]',
                [deps.recommendedOllamaProfile.fast]: 'gpt-oss:20b-cloud  [Recommended]',
                [deps.recommendedOllamaProfile.fallback]: 'qwen3.5:9b  [Recommended]',
            };

            const ensureForSelect = (select, includeNone) => {
                if (!select) return;
                const currentValues = new Set(Array.from(select.querySelectorAll('option')).map((option) => option.value));
                const missing = recommendedValues.filter((value) => value && !currentValues.has(value));
                if (!missing.length) return;
                let group = select.querySelector('optgroup[label="Recommended"]');
                if (!group) {
                    group = document.createElement('optgroup');
                    group.label = 'Recommended';
                    if (includeNone && select.firstChild) {
                        select.appendChild(group);
                    } else {
                        select.appendChild(group);
                    }
                }
                for (const value of missing) {
                    const option = document.createElement('option');
                    option.value = value;
                    option.textContent = labels[value] || value;
                    group.appendChild(option);
                }
            };

            ensureForSelect(deps.refs.modelSelect, false);
            ensureForSelect(deps.refs.fastModelSelect, true);
            ensureForSelect(deps.refs.fallbackModelSelect, true);
        }

        function setOllamaCloudNote(message, isOk) {
            if (!deps.refs.ollamaCloudNote) return;
            deps.refs.ollamaCloudNote.textContent = message || '';
            deps.refs.ollamaCloudNote.className = 'settings-note' + (message ? (isOk ? ' ok' : '') : '');
        }

        function syncModelLoadingUi() {
            const availableModels = deps.getAvailableModels();
            const waitingForModels = deps.getModelsLoading() && availableModels.length === 0;
            if (deps.refs.composerSendBtn) {
                deps.refs.composerSendBtn.disabled = waitingForModels;
                deps.refs.composerSendBtn.title = waitingForModels ? 'One moment — spinning up all systems…' : '';
            }
        }

        function applyRecommendedOllamaProfile() {
            const settings = getSettings();
            settings.main_model = deps.recommendedOllamaProfile.main;
            settings.fast_model = deps.recommendedOllamaProfile.fast;
            settings.fallback_model = deps.recommendedOllamaProfile.fallback;
            ensureRecommendedModelOptions();
            applyModelSettingsToUi();
            setOllamaCloudNote('Recommended Ollama profile selected. Save Settings to persist it.', true);
        }

        function applyModelSettingsToUi() {
            const settings = getSettings();
            const availableModels = deps.getAvailableModels();
            const modelsLoading = deps.getModelsLoading();

            ensureRecommendedModelOptions();
            if (deps.refs.modelSelect) deps.refs.modelSelect.value = settings.main_model || '';
            if (deps.refs.fastModelSelect) deps.refs.fastModelSelect.value = settings.fast_model || '';
            if (deps.refs.fallbackModelSelect) deps.refs.fallbackModelSelect.value = settings.fallback_model || '';
            updateModelLabel();

            const hasMain = availableModels.some((model) => model.id === (settings.main_model || ''));
            const noModels = availableModels.length === 0;
            const message = (modelsLoading && noModels)
                ? 'One moment — spinning up all systems…'
                : noModels
                    ? '⚠ No models available. Start Ollama or add a cloud model to continue.'
                    : (!hasMain ? '⚠ Selected main model is not currently available. Sign in to Ollama Cloud and/or pull the recommended models.' : '');

            if (deps.refs.modelWarning) {
                deps.refs.modelWarning.style.display = message ? 'block' : 'none';
                deps.refs.modelWarning.textContent = message;
                deps.refs.modelWarning.style.color = (message && !modelsLoading) ? 'var(--danger)' : 'var(--text-1)';
                deps.refs.modelWarning.style.fontWeight = (modelsLoading && noModels) ? '700' : '500';
            }
            if (deps.refs.settingsModelWarning) {
                deps.refs.settingsModelWarning.textContent = message || 'Choose which model(s) the AgentOrchestrator should use.';
                deps.refs.settingsModelWarning.className = 'settings-note' + ((message && !modelsLoading) ? ' err' : '');
            }
        }

        async function loadModels(refresh) {
            const settings = getSettings();
            deps.setModelsLoading(true);
            syncModelLoadingUi();
            deps.onModelUiStateChange();
            applyModelSettingsToUi();
            try {
                const url = refresh ? `${deps.getBackendUrl()}/api/models?refresh=true` : `${deps.getBackendUrl()}/api/models`;
                const data = await deps.authFetchJson(url);
                const availableModels = Array.isArray(data.models) ? data.models : [];
                deps.setAvailableModels(availableModels);

                const buildOptions = (select, includeNone) => {
                    if (!select) return;
                    select.innerHTML = includeNone ? '<option value="">Same as main model</option>' : '';
                    if (availableModels.length === 0) {
                        if (!includeNone) select.innerHTML = '<option value="">No models found</option>';
                        return;
                    }
                    const groups = {};
                    availableModels.forEach((model) => {
                        const source = model.source || 'ollama';
                        if (!groups[source]) groups[source] = [];
                        groups[source].push(model);
                    });
                    const labels = { ollama: 'Local (Ollama)', llamacpp: 'Local (llama.cpp)', nvidia: 'NVIDIA Cloud', openai: 'OpenAI', gemini: 'Google Gemini' };
                    Object.entries(groups).forEach(([source, models]) => {
                        const optgroup = document.createElement('optgroup');
                        optgroup.label = labels[source] || source;
                        models.forEach((model) => {
                            const option = document.createElement('option');
                            option.value = model.id;
                            option.textContent = model.label || model.id;
                            optgroup.appendChild(option);
                        });
                        select.appendChild(optgroup);
                    });
                };

                buildOptions(deps.refs.modelSelect, false);
                buildOptions(deps.refs.fastModelSelect, true);
                buildOptions(deps.refs.fallbackModelSelect, true);

                ensureRecommendedModelOptions();

                if (!settings.main_model) settings.main_model = deps.recommendedOllamaProfile.main;
                if (!settings.fast_model) settings.fast_model = deps.recommendedOllamaProfile.fast;
                if (!settings.fallback_model) settings.fallback_model = deps.recommendedOllamaProfile.fallback;
            } catch {
                deps.setAvailableModels([]);
                if (deps.refs.modelSelect) deps.refs.modelSelect.innerHTML = '<option value="">Cannot reach backend</option>';
                if (deps.refs.fastModelSelect) deps.refs.fastModelSelect.innerHTML = '<option value="">Same as main model</option>';
                if (deps.refs.fallbackModelSelect) deps.refs.fallbackModelSelect.innerHTML = '<option value="">No fallback</option>';
            } finally {
                deps.setModelsLoading(false);
                syncModelLoadingUi();
                deps.onModelUiStateChange();
                applyModelSettingsToUi();
            }
        }

        async function loadOllamaLibrary() {
            if (!deps.refs.ollamaLibrarySelect) return;
            try {
                const data = await deps.authFetchJson('/api/ollama/library');
                const models = data.models || [];
                deps.refs.ollamaLibrarySelect.innerHTML = '';
                const placeholder = document.createElement('option');
                placeholder.value = '';
                placeholder.textContent = '— Select a model to download —';
                deps.refs.ollamaLibrarySelect.appendChild(placeholder);
                let hasOptions = false;
                for (const model of models) {
                    const notInstalled = model.tags.filter((tag) => !tag.installed);
                    if (notInstalled.length === 0) continue;
                    const group = document.createElement('optgroup');
                    group.label = `${model.name}  —  ${model.desc}`;
                    for (const tag of notInstalled) {
                        const option = document.createElement('option');
                        option.value = tag.full;
                        option.textContent = tag.full;
                        group.appendChild(option);
                        hasOptions = true;
                    }
                    deps.refs.ollamaLibrarySelect.appendChild(group);
                }
                if (!hasOptions) placeholder.textContent = 'All popular models are installed';
                if (deps.refs.ollamaPullBtn) deps.refs.ollamaPullBtn.disabled = true;
            } catch {
                deps.refs.ollamaLibrarySelect.innerHTML = '<option value="">Could not load Ollama library</option>';
            }
        }

        function showPullStatus(message, type) {
            if (!deps.refs.ollamaPullStatus) return;
            deps.refs.ollamaPullStatus.style.display = message ? '' : 'none';
            deps.refs.ollamaPullStatus.textContent = message;
            deps.refs.ollamaPullStatus.style.color = type === 'error' ? 'var(--danger)'
                : type === 'done' ? '#10b981' : 'var(--accent)';
        }

        async function pullOllamaModel(modelName) {
            if (!modelName) return;
            showPullStatus(`Pulling ${modelName}...`, 'pulling');
            try {
                const response = await deps.authFetch('/api/ollama/pull', {
                    method: 'POST',
                    headers: { 'Content-Type': 'application/json' },
                    body: JSON.stringify({ model: modelName }),
                });
                const data = await response.json();
                if (!response.ok || data.ok === false) {
                    showPullStatus(data.error || `Failed to start pull for ${modelName}`, 'error');
                    return;
                }
                startPullPolling();
            } catch {
                showPullStatus(`Failed to start pull for ${modelName}`, 'error');
            }
        }

        async function pullRecommendedOllamaProfile() {
            const targets = [
                deps.recommendedOllamaProfile.main,
                deps.recommendedOllamaProfile.fast,
                deps.recommendedOllamaProfile.fallback,
            ].filter(Boolean);
            const missing = targets.filter((model) => !currentOllamaInstalledModels.includes(model));
            if (!missing.length) {
                setOllamaCloudNote('Recommended model profile is already available.', true);
                return;
            }
            setOllamaCloudNote('Starting sync for the recommended model profile. If a cloud model fails, run ollama signin first.');
            for (const model of missing) {
                await pullOllamaModel(model);
            }
        }

        function startPullPolling() {
            if (ollamaPullPollingId) return;
            ollamaPullPollingId = setInterval(async () => {
                try {
                    const data = await deps.authFetchJson('/api/ollama/pull/status');
                    const pulls = data.pulls || {};
                    let anyActive = false;
                    const messages = [];
                    for (const [model, info] of Object.entries(pulls)) {
                        if (info.status === 'pulling') {
                            anyActive = true;
                            messages.push(`${model}: ${info.progress > 0 ? info.progress + '%' : 'starting...'}`);
                        } else if (info.status === 'done') {
                            messages.push(`${model}: done ✓`);
                        } else if (info.status === 'error') {
                            messages.push(`${model}: error ✗`);
                        }
                    }
                    showPullStatus(messages.join('  ·  '), anyActive ? 'pulling' : 'done');
                    if (!anyActive) {
                        clearInterval(ollamaPullPollingId);
                        ollamaPullPollingId = null;
                        await loadModels(true);
                        await loadOllamaLibrary();
                        await loadOllamaInstalled();
                        setTimeout(() => showPullStatus('', ''), 4000);
                    }
                } catch {
                    clearInterval(ollamaPullPollingId);
                    ollamaPullPollingId = null;
                }
            }, 2000);
        }

        async function loadOllamaInstalled() {
            if (!deps.refs.ollamaInstalledList) return;
            try {
                const data = await deps.authFetchJson('/api/ollama/installed');
                const ollamaModels = data.models || [];
                currentOllamaInstalledModels = Array.isArray(ollamaModels) ? [...ollamaModels] : [];
                deps.refs.ollamaInstalledList.innerHTML = '';

                const cloudGroups = {};
                for (const model of deps.getAvailableModels()) {
                    if (model.source && model.source !== 'ollama') {
                        if (!cloudGroups[model.source]) cloudGroups[model.source] = [];
                        cloudGroups[model.source].push(model);
                    }
                }
                const sourceLabels = { nvidia: 'NVIDIA', openai: 'OpenAI', gemini: 'Gemini' };
                for (const [source, sourceModels] of Object.entries(cloudGroups)) {
                    const chip = document.createElement('span');
                    chip.className = 'ollama-installed-chip cloud-chip';
                    chip.textContent = `☁ ${sourceLabels[source] || source} (${sourceModels.length})`;
                    chip.title = sourceModels.map((model) => model.label || model.id).join('\n');
                    deps.refs.ollamaInstalledList.appendChild(chip);
                }

                for (const name of ollamaModels) {
                    const chip = document.createElement('span');
                    chip.className = 'ollama-installed-chip';
                    chip.innerHTML = `${name}<button class="chip-delete" title="Delete ${name}">&times;</button>`;
                    chip.querySelector('.chip-delete').addEventListener('click', () => deleteOllamaModel(name, chip));
                    deps.refs.ollamaInstalledList.appendChild(chip);
                }

                if (ollamaModels.length === 0 && Object.keys(cloudGroups).length === 0) {
                    deps.refs.ollamaInstalledList.innerHTML = '<span class="settings-note">No models available</span>';
                }
            } catch {
                currentOllamaInstalledModels = [];
                deps.refs.ollamaInstalledList.innerHTML = '<span class="settings-note">Could not load models</span>';
            }
        }

        async function deleteOllamaModel(modelName, chipEl) {
            if (!confirm(`Delete model "${modelName}"?`)) return;
            const button = chipEl.querySelector('.chip-delete');
            button.disabled = true;
            button.style.opacity = '0.4';
            try {
                const response = await deps.authFetch('/api/ollama/delete', {
                    method: 'POST',
                    headers: { 'Content-Type': 'application/json' },
                    body: JSON.stringify({ model: modelName }),
                }).then((result) => result.json());
                if (response.ok) {
                    chipEl.remove();
                    await loadModels(true);
                    await loadOllamaLibrary();
                    await loadOllamaInstalled();
                } else {
                    alert(`Failed to delete: ${response.error || 'unknown error'}`);
                    button.disabled = false;
                    button.style.opacity = '';
                }
            } catch {
                alert('Failed to delete model');
                button.disabled = false;
                button.style.opacity = '';
            }
        }

        function bindOllamaUi() {
            if (deps.refs.ollamaLibrarySelect && deps.refs.ollamaPullBtn) {
                deps.refs.ollamaLibrarySelect.addEventListener('change', () => {
                    deps.refs.ollamaPullBtn.disabled = !deps.refs.ollamaLibrarySelect.value;
                });
            }
            if (deps.refs.ollamaPullBtn) {
                deps.refs.ollamaPullBtn.addEventListener('click', () => {
                    const model = deps.refs.ollamaLibrarySelect?.value;
                    if (model) {
                        deps.refs.ollamaPullBtn.disabled = true;
                        pullOllamaModel(model);
                    }
                });
            }
            if (deps.refs.ollamaLibraryRefresh) {
                deps.refs.ollamaLibraryRefresh.addEventListener('click', () => loadOllamaLibrary());
            }
            if (deps.refs.ollamaCustomPullBtn && deps.refs.ollamaCustomModel) {
                deps.refs.ollamaCustomPullBtn.addEventListener('click', () => {
                    const name = deps.refs.ollamaCustomModel.value.trim();
                    if (!name) return;
                    deps.refs.ollamaCustomPullBtn.disabled = true;
                    deps.refs.ollamaCustomPullBtn.textContent = 'Pulling...';
                    pullOllamaModel(name);
                    deps.refs.ollamaCustomModel.value = '';
                    deps.refs.ollamaCustomPullBtn.disabled = false;
                    deps.refs.ollamaCustomPullBtn.textContent = 'Pull';
                });
            }
            if (deps.refs.ollamaApplyRecommendedBtn) {
                deps.refs.ollamaApplyRecommendedBtn.addEventListener('click', () => {
                    applyRecommendedOllamaProfile();
                });
            }
            if (deps.refs.ollamaPullRecommendedBtn) {
                deps.refs.ollamaPullRecommendedBtn.addEventListener('click', async () => {
                    deps.refs.ollamaPullRecommendedBtn.disabled = true;
                    try {
                        await pullRecommendedOllamaProfile();
                    } finally {
                        deps.refs.ollamaPullRecommendedBtn.disabled = false;
                    }
                });
            }
        }

        return {
            refreshProviderNotes,
            updateModelLabel,
            applyModelSettingsToUi,
            loadModels,
            loadOllamaLibrary,
            pullOllamaModel,
            pullRecommendedOllamaProfile,
            loadOllamaInstalled,
            deleteOllamaModel,
            bindOllamaUi,
        };
    };
})();