/**
 * Contentosapp Studio Admin — Settings integrations/search/language interactions.
 */
/* global CostudioData */
(function ($) {
    'use strict';

    var data = window.CostudioData || {};
    var ajax = data.ajax_url || '';
    var nonce = data.nonce || '';
    var i18n = data.i18n || {};
    function t(key, fallback) {
        return (typeof i18n[key] === 'string' && i18n[key].length) ? i18n[key] : fallback;
    }

    if (!$("#fos-settings-ai-form, #fos-settings-lang-form, #fos-search-test-connection").length) {
        return;
    }

    function esc(str) {
        return $('<div>').text(str).html();
    }

    function fosAutoHideResult($el, delayMs, onHidden) {
        if (!$el || !$el.length) { return; }
        var t = parseInt($el.data('hideTimer') || 0, 10);
        if (t) {
            window.clearTimeout(t);
        }
        var timer = window.setTimeout(function () {
            $el.fadeOut(180, function () {
                $el.text('').removeClass('is-success is-error');
                if (typeof onHidden === 'function') { onHidden(); }
            });
        }, delayMs || 3200);
        $el.data('hideTimer', timer);
    }

    // ── Settings: save AI provider settings ──────────────────────────────────

    $(document).on('submit', '#fos-settings-ai-form', function (e) {
        e.preventDefault();
        var $form = $(this);
        var $btn = $form.find('button[type="submit"]');
        var orig = $btn.text();
        var $msg = $('#fos-settings-ai-msg');

        $btn.text('…').prop('disabled', true);
        $msg.text('').removeClass('is-success is-error');

        var formData = $form.serializeArray();
        formData.push({ name: 'action', value: 'costudio_save_settings' });
        formData.push({ name: 'nonce', value: nonce });

        $.post(ajax, formData)
            .done(function (res) {
                if (res.success) {
                    $msg.text(res.data || t('saved', 'Saved!')).addClass('is-success');
                    $(document).trigger('fos:ai-settings-saved');

                    // Keep current model selection and in-page model cache after save.
                    // The backend already decides when DB cache must be invalidated.
                    $('#fos-ai-model').data('current', $('#fos-ai-model').val());
                } else {
                    $msg.text(res.data || t('error', 'Error')).addClass('is-error');
                }
                $btn.text(orig).prop('disabled', false);
                setTimeout(function () { $msg.text('').removeClass('is-success is-error'); }, 3000);
            })
            .fail(function () {
                $msg.text(t('error', 'Error')).addClass('is-error');
                $btn.text(orig).prop('disabled', false);
            });
    });

    // ── Settings: AI — toggle API key visibility ──────────────────────────────

    $(document).on('click', '.fos-int-toggle-vis', function () {
        var targetId = $(this).data('target');
        var $input = $('#' + targetId);
        var isPassword = $input.attr('type') === 'password';
        $input.attr('type', isPassword ? 'text' : 'password');
        $(this).find('.dashicons')
            .toggleClass('dashicons-visibility', !isPassword)
            .toggleClass('dashicons-hidden', isPassword);
    });

    // ── Settings: AI — populate model select from cache ──────────────────────

    function fosPopulateModelSelect(models, currentValue) {
        var $select = $('#fos-ai-model');
        var $hint = $('#fos-ai-model-hint');
        if (!models || !models.length) {
            $select.html('<option value="">' + t('click_to_load', '— Click 🔄 to load —') + '</option>');
            $hint.text(t('models_hint', 'Click 🔄 to load available models from API.'));
            return;
        }
        var current = currentValue || $select.data('current') || $select.val();
        var options = '';
        $.each(models, function (_, m) {
            var sel = (m.value === current) ? ' selected' : '';
            options += '<option value="' + esc(m.value) + '"' + sel + '>' + esc(m.label) + '</option>';
        });
        $select.html(options);
        $select.data('current', $select.val());
        $hint.text(models.length + ' ' + t('models_loaded', 'models available. Click 🔄 to refresh.'));
    }

    // When provider changes, swap model options from cache (if available).
    $(document).on('change', '#ai_provider', function () {
        var provider = $(this).val();
        var cache = (data.models_cache && data.models_cache[provider]) ? data.models_cache[provider] : null;
        fosPopulateModelSelect(cache, '');
        fosUpdateProviderTip(provider);
    });

    function fosUpdateProviderTip(provider) {
        var $container = $('#fos-provider-tip-container');
        if (!$container.length) return;

        var tips = {
            'gemini': {
                icon: '💡',
                text: t('tip_gemini', 'Google Gemini offers a free tier for initial testing. Create your key at aistudio.google.com.')
            },
            'openai': {
                icon: '⚡',
                text: t('tip_openai', 'Pay as you go. GPT-4o has strong performance for structured writing and English content.')
            },
            'anthropic': {
                icon: '✨',
                text: t('tip_claude', 'Pay as you go. Claude is excellent for maintaining tone consistency in long-form articles.')
            },
            'claude': {
                icon: '✨',
                text: t('tip_claude', 'Pay as you go. Claude is excellent for maintaining tone consistency in long-form articles.')
            }
        };

        var tip = tips[provider];
        if (tip) {
            $container.find('.fos-provider-tip-icon').text(tip.icon);
            renderTipText($container.find('.fos-provider-tip-content'), tip.text);
            $container.show();
        } else {
            $container.find('.fos-provider-tip-icon').text('ℹ️');
            renderTipText($container.find('.fos-provider-tip-content'), t('tip_select_provider', 'Select a provider to see details and usage recommendations.'));
            $container.show();
        }
    }

    /**
     * Render tip text inside a container, turning known URL tokens into anchor
     * elements without ever using innerHTML — protects against future strings
     * accidentally carrying HTML payloads.
     */
    function renderTipText($container, rawText) {
        var $node = $container.first();
        if (!$node.length) return;
        $node.empty();

        // Domains that should be auto-linked when they appear in tip strings.
        var linkable = [
            { match: 'aistudio.google.com', href: 'https://aistudio.google.com' }
        ];

        var pattern = linkable.map(function (l) {
            return l.match.replace(/\./g, '\\.');
        }).join('|');
        var splitter = new RegExp('(' + pattern + ')');

        var parts = rawText.split(splitter);
        var el = $node[0];

        parts.forEach(function (part) {
            var hit = linkable.find(function (l) { return l.match === part; });
            if (hit) {
                var a = document.createElement('a');
                a.href = hit.href;
                a.target = '_blank';
                a.rel = 'noopener noreferrer';
                a.textContent = part;
                a.style.color = '#6C47FF';
                a.style.textDecoration = 'none';
                el.appendChild(a);
            } else {
                el.appendChild(document.createTextNode(part));
            }
        });
    }

    // Init provider tip on load
    fosUpdateProviderTip($('#ai_provider').val());

    // ── Settings: AI — Init saved models on load ──────────────────────────────
    var initialProvider = $('#ai_provider').val();
    if (initialProvider && data.models_cache && data.models_cache[initialProvider]) {
        fosPopulateModelSelect(data.models_cache[initialProvider], $('#fos-ai-model').data('current') || $('#fos-ai-model').val());
    }

    var initialImgProvider = $('#fos-image-provider').val();
    if (initialImgProvider && data.image_models_cache && data.image_models_cache[initialImgProvider]) {
        fosPopulateImageModelSelect(data.image_models_cache[initialImgProvider], $('#fos-image-model').data('current') || $('#fos-image-model').val());
    }
    // Seed `data-byok-last` so that toggling ContentOS Auto → BYOK can restore
    // the previously saved BYOK provider instead of clearing the dropdown.
    if (initialImgProvider && initialImgProvider !== 'contentos') {
        $('#fos-image-provider').attr('data-byok-last', initialImgProvider);
    }

    // Live status badges — update on input/select changes so the user sees
    // immediate feedback without having to save first.
    $(document).on('input change', '#fos-ai-api-key', function () {
        if (typeof window.fosUpdateAiStatusBadge === 'function') {
            window.fosUpdateAiStatusBadge($('#fos-ai-mode-input').val() || 'contentos');
        }
    });
    $(document).on('input change', '#fos-image-api-key, #fos-image-provider, #fos-img-mode-value', function () {
        if (typeof window.fosUpdateImgStatusBadge === 'function') {
            window.fosUpdateImgStatusBadge();
        }
    });
    $(document).on('click', '.fos-img-mode-card', function () {
        // Card click changes #fos-img-mode-value; defer to next tick so the
        // hidden value is already set when we read it.
        window.setTimeout(function () {
            if (typeof window.fosUpdateImgStatusBadge === 'function') {
                window.fosUpdateImgStatusBadge();
            }
        }, 0);
    });

    // ── Settings: AI — fetch models from provider API ─────────────────────────

    $(document).on('click', '#fos-ai-fetch-models', function () {
        var $btn = $(this);
        var $hint = $('#fos-ai-model-hint');
        var provider = $('#ai_provider').val();
        var apiKey = $('#fos-ai-api-key').val();
        var current = $('#fos-ai-model').data('current') || $('#fos-ai-model').val();

        $btn.addClass('is-loading').text('⏳');
        $hint.text(t('loading', 'Loading…'));

        $.post(ajax, {
            action: 'costudio_fetch_models',
            nonce: nonce,
            provider: provider,
            api_key: apiKey,
        })
            .done(function (res) {
                if (!res.success || !res.data || !res.data.length) {
                    $hint.text(res.data || t('models_fetch_error', 'Error fetching models.'));
                    return;
                }
                // Update in-page cache so provider switching works within the session.
                if (!data.models_cache) { data.models_cache = {}; }
                data.models_cache[provider] = res.data;
                fosPopulateModelSelect(res.data, current);
            })
            .fail(function () {
                $hint.text(t('models_fetch_failed', 'Failed to fetch models.'));
            })
            .always(function () {
                $btn.removeClass('is-loading').text('🔄');
            });
    });

    // ── Settings: AI — test connection ────────────────────────────────────────

    $(document).on('click', '#fos-ai-test-connection', function () {
        var $btn = $(this);
        var $result = $('#fos-ai-test-result');
        var $hint = $('#fos-ai-api-hint');
        var orig = $btn.html();

        $btn.prop('disabled', true).html('⏳ ' + t('testing', 'Testing…'));
        $result.text('').removeClass('is-success is-error').hide();

        $.post(ajax, {
            action: 'costudio_test_ai_connection',
            nonce: nonce,
            provider: $('#ai_provider').val(),
            api_key: $('#fos-ai-api-key').val(),
            model: $('#fos-ai-model').val(),
        })
            .done(function (res) {
                $hint.hide();
                if (res.success) {
                    $result.text(res.data || t('connected_check', '✓ Connected!')).addClass('is-success').css('display', '');
                    $('#fos-ai-status')
                        .removeClass('fos-int-status--warn')
                        .addClass('fos-int-status--ok')
                        .find('.fos-int-status__text')
                        .text(t('api_key_saved', 'API key saved'));
                    fosAutoHideResult($result, 3200, function () { $hint.show(); });
                } else {
                    $result.text('✕ ' + (res.data || t('error', 'Error'))).addClass('is-error').css('display', '');
                    fosAutoHideResult($result, 4200, function () { $hint.show(); });
                }
            })
            .fail(function () {
                $hint.hide();
                $result.text('✕ ' + t('request_failed', 'Request failed.')).addClass('is-error').css('display', '');
                fosAutoHideResult($result, 4200, function () { $hint.show(); });
            })
            .always(function () {
                $btn.prop('disabled', false).html(orig);
            });
    });

    // ── Settings: AI — update status dot after successful save ────────────────

    $(document).on('fos:ai-settings-saved', function () {
        var $apiKey = $('#fos-ai-api-key');
        if ($apiKey.val() && $apiKey.val().indexOf('•') === -1) {
            $('#fos-ai-status')
                .removeClass('fos-int-status--warn')
                .addClass('fos-int-status--ok')
                .find('.fos-int-status__text')
                .text(t('api_key_saved', 'API key saved'));
        }
    });

    // ── Settings: Images — model select/cache helpers ────────────────────────

    function fosNormalizeModelRow(model) {
        if (!model) { return null; }
        var value = (typeof model.value !== 'undefined') ? String(model.value).trim() : '';
        if (!value) { return null; }
        var label = (typeof model.label !== 'undefined') ? String(model.label).trim() : value;
        if (!label) { label = value; }
        if (label.toLowerCase() !== value.toLowerCase() && label.toLowerCase().indexOf(value.toLowerCase()) === -1) {
            label += ' - ' + value;
        }
        if (/^imagen-4\.0-/i.test(value) && label.toLowerCase().indexOf('deprecated') === -1) {
            label += ' (deprecated Aug 17, 2026)';
        }
        return $.extend({}, model, { value: value, label: label });
    }

    function fosNormalizeModelRows(models) {
        var normalized = [];
        $.each(models || [], function (_, model) {
            var row = fosNormalizeModelRow(model);
            if (row) { normalized.push(row); }
        });
        return normalized;
    }

    function fosUpdateSelectedImageModel() {
        var $select = $('#fos-image-model');
        var $target = $('#fos-image-selected-model');
        if (!$select.length || !$target.length) { return; }

        var value = $select.val() || '';
        $target.empty();

        if (!value) {
            $target.hide();
            return;
        }

        $target
            .append(document.createTextNode(t('selected_model', 'Selected model') + ': '))
            .append($('<code>').text(value))
            .show();
    }

    function fosPopulateImageModelSelect(models, currentValue) {
        var $select = $('#fos-image-model');
        var $hint = $('#fos-image-model-hint');
        if (!$select.length) { return; }
        models = fosNormalizeModelRows(models);
        if (!models || !models.length) {
            $select.html('<option value="">' + t('select_provider_first_option', '— Select a provider first —') + '</option>');
            $hint.text(t('models_hint', 'Click 🔄 to load available models from API.'));
            fosUpdateSelectedImageModel();
            return;
        }
        var current = currentValue || $select.data('current') || $select.val();
        var options = '';
        $.each(models, function (_, m) {
            var sel = (m.value === current) ? ' selected' : '';
            options += '<option value="' + esc(m.value) + '"' + sel + '>' + esc(m.label) + '</option>';
        });
        $select.html(options);
        $select.data('current', $select.val());
        $hint.text(models.length + ' ' + t('models_loaded', 'models available. Click 🔄 to refresh.'));
        fosUpdateSelectedImageModel();
    }

    $(document).on('change', '#fos-image-provider', function () {
        var provider = $(this).val();
        var cache = (data.image_models_cache && data.image_models_cache[provider]) ? data.image_models_cache[provider] : null;
        fosPopulateImageModelSelect(cache, '');

        if (provider === 'contentos') {
            $('#fos-image-api-key-block').css({ opacity: 0.45, pointerEvents: 'none' });
        } else {
            $('#fos-image-api-key-block').css({ opacity: '', pointerEvents: '' });
        }
    });

    $(document).on('change', '#fos-image-model', function () {
        $(this).data('current', $(this).val());
        fosUpdateSelectedImageModel();
    });

    fosUpdateSelectedImageModel();

    $(document).on('click', '#fos-image-fetch-models', function () {
        var $btn = $(this);
        var $hint = $('#fos-image-model-hint');
        var provider = $('#fos-image-provider').val();
        var apiKey = $('#fos-image-api-key').val();
        var current = $('#fos-image-model').data('current') || $('#fos-image-model').val();

        if (!provider) {
            $hint.text(t('select_provider_first', 'Select a provider first.'));
            return;
        }

        $btn.addClass('is-loading').text('⏳');
        $hint.text(t('loading', 'Loading…'));

        $.post(ajax, {
            action: 'costudio_fetch_image_models',
            nonce: nonce,
            provider: provider,
            api_key: apiKey
        })
            .done(function (res) {
                if (!res.success || !res.data || !res.data.length) {
                    $hint.text(res.data || t('models_fetch_error', 'Error fetching models.'));
                    return;
                }
                if (!data.image_models_cache) { data.image_models_cache = {}; }
                data.image_models_cache[provider] = fosNormalizeModelRows(res.data);
                fosPopulateImageModelSelect(data.image_models_cache[provider], current);
            })
            .fail(function () {
                $hint.text(t('models_fetch_failed', 'Failed to fetch models.'));
            })
            .always(function () {
                $btn.removeClass('is-loading').text('🔄');
            });
    });

    // ── Settings: Images — test connection ───────────────────────────────────

    $(document).on('click', '#fos-image-test-connection', function () {
        var $btn = $(this);
        var $result = $('#fos-image-test-result');
        var orig = $btn.html();

        var $hint = $('#fos-image-api-hint');

        $btn.prop('disabled', true).html('⏳ ' + t('testing', 'Testing…'));
        $result.text('').removeClass('is-success is-error').hide();

        $.post(ajax, {
            action: 'costudio_test_image_connection',
            nonce: nonce,
            provider: $('#fos-image-provider').val(),
            api_key: $('#fos-image-api-key').val(),
            model: $('#fos-image-model').val()
        })
            .done(function (res) {
                $hint.hide();
                if (res.success) {
                    $result.text(res.data || t('connected_check', '✓ Connected!')).addClass('is-success').css('display', '');
                    $('#fos-image-status')
                        .removeClass('fos-int-status--warn')
                        .addClass('fos-int-status--ok')
                        .find('.fos-int-status__text')
                        .text(t('api_key_saved', 'API key saved'));
                    fosAutoHideResult($result, 3200, function () { $hint.show(); });
                } else {
                    $result.text('✕ ' + (res.data || t('error', 'Error'))).addClass('is-error').css('display', '');
                    fosAutoHideResult($result, 4200, function () { $hint.show(); });
                }
            })
            .fail(function () {
                $hint.hide();
                $result.text('✕ ' + t('request_failed', 'Request failed.')).addClass('is-error').css('display', '');
                fosAutoHideResult($result, 4200, function () { $hint.show(); });
            })
            .always(function () {
                $btn.prop('disabled', false).html(orig);
            });
    });

    // ── Settings: Search — grounding/external behavior ───────────────────────

    var fosSearchCuratedModels = {
        exa: [
            { value: 'auto', label: 'Auto (Recommended)' },
            { value: 'fast', label: 'Fast' },
            { value: 'deep', label: 'Deep' }
        ],
        serper: [
            { value: 'search', label: 'Web (Default)' },
            { value: 'news', label: 'News' }
        ],
        tavily: [
            { value: 'advanced', label: 'Advanced (Recommended)' },
            { value: 'basic', label: 'Basic' }
        ]
    };

    var fosSearchProviderSchema = {
        gemini: {
            modelLabel: 'Model',
            results: false,
            tip: 'Gemini uses the selected grounding model and returns raw grounding context in BYOK.'
        },
        tavily: {
            modelLabel: 'Depth',
            results: true,
            tip: 'Tavily uses Basic or Advanced depth and returns structured sources.'
        },
        serper: {
            modelLabel: 'Type',
            results: true,
            tip: 'Serper switches between Web and News results and returns structured sources.'
        },
        exa: {
            modelLabel: 'Mode',
            results: true,
            tip: 'Exa supports Auto, Fast and Deep search modes and returns structured sources.'
        }
    };

    function fosNormalizeSearchModelValue(provider, value) {
        var model = String(value || '').trim().toLowerCase();
        if (provider === 'exa') {
            if (model.indexOf('exa:') === 0) {
                model = model.substring(4);
            }
            if (model === 'neural' || model === 'keyword') {
                return 'auto';
            }
            return (model === 'auto' || model === 'fast' || model === 'deep') ? model : 'auto';
        }
        if (provider === 'tavily') {
            return (model === 'basic' || model === 'advanced') ? model : 'advanced';
        }
        if (provider === 'serper') {
            return (model === 'search' || model === 'news') ? model : 'search';
        }
        return String(value || '').trim();
    }

    function fosSearchModelsForProvider(provider, models) {
        if (fosSearchCuratedModels[provider]) {
            return fosSearchCuratedModels[provider];
        }
        return models || [];
    }

    function fosUpdateSearchProviderFields(provider) {
        var schema = fosSearchProviderSchema[provider] || null;
        var hasProvider = !!schema;
        $('#fos-search-model-block').toggle(hasProvider);
        $('#fos-search-results-block').toggle(hasProvider && !!schema.results);
        $('#fos-search-provider-tip').toggle(hasProvider && !schema.results);
        if (!hasProvider) { return; }

        $('#fos-search-model-label').text(schema.modelLabel);
        $('#fos-search-provider-tip .fos-provider-tip-content').text(schema.tip);
    }

    function fosSyncSearchGroundingUI() {
        var globalMode = $('#fos-ai-mode-input').val() || 'contentos';
        var groundingOn = $('#fos-search-grounding').is(':checked');
        var $external = $('#fos-search-external-fields');
        if (!$external.length) { return; }

        if (globalMode === 'contentos' || groundingOn) {
            $external.hide();
        } else {
            $external.show();
        }
        fosUpdateSearchProviderFields($('#fos-search-provider').val() || '');

        var $statusText = $('#fos-search-status .fos-int-status__text');
        var $statusWrap = $('#fos-search-status');
        if ($statusText.length) {
            if (globalMode === 'contentos' && groundingOn) {
                $statusText.text(t('grounding_active', 'Grounding active'));
                $statusWrap.removeClass('fos-int-status--warn').addClass('fos-int-status--ok');
            } else if (globalMode === 'contentos') {
                $statusText.text(t('search_disabled', 'Search disabled'));
                $statusWrap.removeClass('fos-int-status--ok').addClass('fos-int-status--warn');
            } else if ($('#fos-search-api-key').val()) {
                $statusText.text(t('api_key_saved', 'API key saved'));
                $statusWrap.removeClass('fos-int-status--warn').addClass('fos-int-status--ok');
            } else {
                $statusText.text(t('api_key_missing', 'API key missing'));
                $statusWrap.removeClass('fos-int-status--ok').addClass('fos-int-status--warn');
            }
        }
    }

    window.fosSyncSearchGroundingUI = fosSyncSearchGroundingUI;

    $(document).on('change', '#fos-search-grounding', function () {
        var globalMode = $('#fos-ai-mode-input').val() || 'contentos';
        var isChecked = $(this).is(':checked');
        var $fields = $('#fos-search-external-fields');
        if (globalMode === 'contentos' || isChecked) {
            $fields.fadeOut(180);
        } else {
            $fields.fadeIn(180);
        }
        fosSyncSearchGroundingUI();
    });

    // Init on first paint.
    fosSyncSearchGroundingUI();

    $(document).on('change', '#fos-search-grounding', function () {
        var globalMode = $('#fos-ai-mode-input').val() || 'contentos';
        var isChecked = $(this).is(':checked');
        var $fields = $('#fos-search-external-fields');
        if (globalMode === 'contentos' || isChecked) {
            $fields.fadeOut(180);
            if (globalMode === 'contentos' && !isChecked) {
                $('#fos-search-status')
                    .removeClass('fos-int-status--ok')
                    .addClass('fos-int-status--warn')
                    .find('.fos-int-status__text')
                    .text(t('search_disabled', 'Search disabled'));
            } else {
                $('#fos-search-status')
                    .removeClass('fos-int-status--warn')
                    .addClass('fos-int-status--ok')
                    .find('.fos-int-status__text')
                    .text(t('grounding_active', 'Grounding active'));
            }
        } else {
            $fields.fadeIn(180);
            // If turning OFF, we don't know if the key is valid yet, but usually 
            // if we were in "BYOK" before, we might want to keep that status.
            // For simplicity, let's keep it but maybe change text if no key.
            if (!$('#fos-search-api-key').val()) {
                $('#fos-search-status').removeClass('fos-int-status--ok').addClass('fos-int-status--warn')
                    .find('.fos-int-status__text').text(t('api_key_missing', 'API key missing'));
            }
        }
    });

    $(document).on('click', '#fos-search-test-connection', function () {
        var $btn = $(this);
        var $result = $('#fos-search-test-result');
        var $hint = $('#fos-search-api-hint');
        var orig = $btn.html();

        $btn.prop('disabled', true).html('⏳ ' + t('testing', 'Testing…'));
        $result.text('').removeClass('is-success is-error').hide();

        $.post(ajax, {
            action: 'costudio_test_search_connection',
            nonce: nonce,
            grounding: $('#fos-search-grounding').is(':checked') ? 1 : 0,
            provider: $('#fos-search-provider').val(),
            api_key: $('#fos-search-api-key').val()
        })
            .done(function (res) {
                $hint.hide();
                if (res.success) {
                    $result.text(res.data || t('connected_check', '✓ Connected!')).addClass('is-success').css('display', '');
                    $('#fos-search-status')
                        .removeClass('fos-int-status--warn')
                        .addClass('fos-int-status--ok')
                        .find('.fos-int-status__text')
                        .text($('#fos-search-grounding').is(':checked') ? t('grounding_active', 'Grounding active') : t('api_key_saved', 'API key saved'));
                    fosAutoHideResult($result, 3200, function () { $hint.show(); });
                } else {
                    $result.text('✕ ' + (res.data || t('error', 'Error'))).addClass('is-error').css('display', '');
                    fosAutoHideResult($result, 4200, function () { $hint.show(); });
                }
            })
            .fail(function () {
                $hint.hide();
                $result.text('✕ ' + t('request_failed', 'Request failed.')).addClass('is-error').css('display', '');
                fosAutoHideResult($result, 4200, function () { $hint.show(); });
            })
            .always(function () {
                $btn.prop('disabled', false).html(orig);
            });
    });

    // ── Settings: Search — model select/cache helpers ────────────────────────

    function fosPopulateSearchModelSelect(models, currentValue) {
        var $select = $('#fos-search-model');
        var $hint = $('#fos-search-model-hint');
        if (!$select.length) { return; }
        var provider = $('#fos-search-provider').val() || '';
        models = fosSearchModelsForProvider(provider, models);
        if (!models || !models.length) {
            $select.html('<option value="">' + t('click_to_load', '— Click 🔄 to load —') + '</option>');
            $hint.text(t('models_hint', 'Click 🔄 to load available models from API.'));
            return;
        }
        var current = fosNormalizeSearchModelValue(provider, currentValue || $select.data('current') || $select.val());
        var options = '';
        $.each(models, function (_, m) {
            var sel = (m.value === current) ? ' selected' : '';
            options += '<option value="' + esc(m.value) + '"' + sel + '>' + esc(m.label) + '</option>';
        });
        $select.html(options);
        $select.data('current', $select.val());
        $hint.text(models.length + ' ' + t('models_loaded', 'models available. Click 🔄 to refresh.'));
    }

    var initialSearchProvider = $('#fos-search-provider').val();
    fosUpdateSearchProviderFields(initialSearchProvider || '');
    if (initialSearchProvider && data.search_models_cache && data.search_models_cache[initialSearchProvider]) {
        fosPopulateSearchModelSelect(data.search_models_cache[initialSearchProvider], $('#fos-search-model').data('current') || $('#fos-search-model').val());
    } else if (initialSearchProvider && fosSearchCuratedModels[initialSearchProvider]) {
        fosPopulateSearchModelSelect(fosSearchCuratedModels[initialSearchProvider], $('#fos-search-model').data('current') || $('#fos-search-model').val());
    }

    $(document).on('change', '#fos-search-provider', function () {
        var provider = $(this).val();
        fosUpdateSearchProviderFields(provider);
        var cache = (data.search_models_cache && data.search_models_cache[provider]) ? data.search_models_cache[provider] : null;
        fosPopulateSearchModelSelect(cache, '');
    });

    $(document).on('click', '#fos-search-fetch-models', function () {
        var $btn = $(this);
        var $hint = $('#fos-search-model-hint');
        var provider = $('#fos-search-provider').val();
        var apiKey = $('#fos-search-api-key').val();
        var current = $('#fos-search-model').data('current') || $('#fos-search-model').val();

        if (!provider) {
            $hint.text(t('select_provider_first', 'Select a provider first.'));
            return;
        }

        $btn.addClass('is-loading').text('⏳');
        $hint.text(t('loading', 'Loading…'));

        $.post(ajax, {
            action: 'costudio_fetch_search_models',
            nonce: nonce,
            provider: provider,
            api_key: apiKey
        })
            .done(function (res) {
                if (!res.success || !res.data || !res.data.length) {
                    $hint.text(res.data || t('models_fetch_error', 'Error fetching models.'));
                    return;
                }
                if (!data.search_models_cache) { data.search_models_cache = {}; }
                data.search_models_cache[provider] = fosSearchModelsForProvider(provider, res.data);
                fosPopulateSearchModelSelect(data.search_models_cache[provider], current);
            })
            .fail(function () {
                $hint.text(t('models_fetch_failed', 'Failed to fetch models.'));
            })
            .always(function () {
                $btn.removeClass('is-loading').text('🔄');
            });
    });

    // ── Settings: save language settings ─────────────────────────────────────

    $(document).on('submit', '#fos-settings-lang-form', function (e) {
        e.preventDefault();
        var $form = $(this);
        var $btn = $form.find('button[type="submit"]');
        var orig = $btn.text();
        var $msg = $('#fos-settings-lang-msg');

        $btn.text('…').prop('disabled', true);
        $msg.text('').removeClass('is-success is-error');

        var formData = $form.serializeArray();
        formData.push({ name: 'action', value: 'costudio_save_settings' });
        formData.push({ name: 'nonce', value: nonce });

        $.post(ajax, formData)
            .done(function (res) {
                if (res.success) {
                    try {
                        sessionStorage.setItem('costudio_active_tab', 'language');
                    } catch (e) { /* ignore */ }
                    window.location.reload();
                    return;
                }
                $msg.text(res.data || t('error', 'Error')).addClass('is-error');
                $btn.text(orig).prop('disabled', false);
                setTimeout(function () { $msg.text('').removeClass('is-success is-error'); }, 3000);
            })
            .fail(function () {
                $msg.text(t('error', 'Error')).addClass('is-error');
                $btn.text(orig).prop('disabled', false);
            });
    });

    // ── Settings: Images — mode selector & quantity stepper ──────────────────

    $(document).on('click', '.fos-img-mode-card', function () {
        var $card = $(this);
        // Ignore clicks inside disabled fieldsets.
        if ($card.closest('fieldset').is('[disabled]') || $card.hasClass('fos-img-mode-card--service-gated')) {
            return;
        }
        var mode = $card.data('mode');

        $('.fos-img-mode-card').removeClass('fos-img-mode-card--active');
        $card.addClass('fos-img-mode-card--active');

        $('.fos-img-section').removeClass('fos-img-section--active');
        $('#fos-img-section-' + mode).addClass('fos-img-section--active');

        $('#fos-img-mode-value').val(mode);
        if (typeof window.fosApplyGlobalExecutionMode === 'function') {
            window.fosApplyGlobalExecutionMode($('#fos-ai-mode-input').val() || 'contentos');
        }
    });

    $(document).on('click', '#fos-img-qty-minus, #fos-img-qty-plus', function () {
        var $valDisplay = $('#fos-img-qty-display');
        var $valInput = $('#fos-img-qty-value');
        var $stepper = $(this).closest('.fos-img-qty-stepper');
        var min = parseInt($stepper.data('min') || 1, 10);
        var max = parseInt($stepper.data('max') || 3, 10);
        var current = parseInt($valInput.val() || 2, 10);
        var isPlus = $(this).attr('id') === 'fos-img-qty-plus';

        current = Math.max(min, Math.min(max, current));

        if (isPlus && current < max) {
            current++;
        } else if (!isPlus && current > min) {
            current--;
        }

        $valDisplay.text(current);
        $valInput.val(current);
    });

    $(document).on('click', '#fos-settings-sync-quota', function (e) {
        e.preventDefault();
        var $btn = $(this);
        if ($btn.hasClass('is-spinning')) return;

        $btn.addClass('is-spinning');
        $('#fos-ai-status-text').css('opacity', 0.5);

        $.post(ajax, {
            action: 'costudio_sync_license_quota',
            nonce: nonce
        }, function (res) {
            $btn.removeClass('is-spinning');
            if (!res.success) {
                alert(res.data || t('sync_failed', 'Sync failed.'));
                $('#fos-ai-status-text').css('opacity', 1);
                return;
            }
            
            // Reload the tab content or just the status text? 
            // Better to reload the whole page or trigger a refresh of the status badge.
            // For now, let's just refresh the page to ensure all PHP constants are updated.
            window.location.reload();
        });
    });
})(jQuery);
