/**
 * Glance Live Search - Admin settings page
 */
jQuery(function ($) {

    var DEFAULT_TAB = 'behavior',
        $tabs   = $('.glse-nav-item'),
        $panels = $('.glse-tab-panel');

    /* ── Tab navigation ── */
    function tabFor(id) {
        return $tabs.filter(function () {
            return String($(this).data('tab')) === String(id);
        });
    }

    function activateTab(id) {
        var $tab = tabFor(id);
        if (!$tab.length) {
            id   = DEFAULT_TAB;
            $tab = tabFor(id);
        }
        if (!$tab.length) return;

        $tabs.removeClass('glse-nav-item--active').attr({ 'aria-selected': 'false', tabindex: '-1' });
        $tab.addClass('glse-nav-item--active').attr({ 'aria-selected': 'true', tabindex: '0' });

        var $panel = $panels.filter('#glse-panel-' + id);
        $panels.removeClass('glse-tab-panel--active');
        $panel.addClass('glse-tab-panel--active');

        /* Show Save only where there is something to save. The old rule
           hardcoded "not the analytics tab", but the retention setting lives
           on that tab - it could be changed and not saved. */
        var savable = $panel.find('[name^="glse_settings["]').not('[type=hidden]').length;
        $('.glse-form-footer').toggle(savable > 0);

        /*
         * The address bar carries the tab, so a reload or a copied link opens
         * the same panel - and the server renders it active, instead of
         * painting the default and letting this function swap it a moment
         * later. replaceState, not pushState: Back should leave the page
         * rather than walk back through the tabs.
         */
        if (window.history.replaceState) {
            var url = new URL(window.location.href);
            url.searchParams.set('tab', id);
            window.history.replaceState(null, '', url.pathname + url.search + url.hash);
        }
    }

    /** The tab currently shown, read from the DOM rather than kept in a variable. */
    function currentTab() {
        return $tabs.filter('.glse-nav-item--active').data('tab') || DEFAULT_TAB;
    }

    $tabs.on('click', function (e) {
        e.preventDefault();
        activateTab($(this).data('tab'));
    });

    /* Arrow-key navigation between tabs (WAI-ARIA tabs pattern). */
    $tabs.on('keydown', function (e) {
        var keys = { ArrowUp: -1, ArrowLeft: -1, ArrowDown: 1, ArrowRight: 1 };
        var step = keys[e.key];
        if (step === undefined && e.key !== 'Home' && e.key !== 'End') return;
        e.preventDefault();

        var i = $tabs.index(this);
        var next = e.key === 'Home' ? 0
                 : e.key === 'End'  ? $tabs.length - 1
                 : (i + step + $tabs.length) % $tabs.length;

        var $next = $tabs.eq(next);
        activateTab($next.data('tab'));
        $next.trigger('focus');
    });

    /* ── Keep active tab after save ──
     * The referer field was rendered with whatever URL the page was loaded
     * under, so switching tabs without reloading leaves it stale. */
    $('.glse-settings-form').on('submit', function () {
        var $ref = $(this).find('input[name="_wp_http_referer"]');
        if (!$ref.length) return;
        var url = new URL($ref.val(), window.location.origin);
        url.searchParams.set('tab', currentTab());
        $ref.val(url.pathname + url.search);
    });

    /*
     * The address bar is the only source of truth for which tab is open.
     *
     * Anything the server cannot read - localStorage, a fragment - leaves it
     * painting the default panel while this call swaps in another, a
     * full-panel flash on the way in. Coming back to a tab after a save goes
     * through the referer field above.
     */
    activateTab((new URLSearchParams(window.location.search)).get('tab') || DEFAULT_TAB);

    /* ── Clean ?settings-updated from URL to prevent notice on refresh ── */
    if (window.history.replaceState && (new URLSearchParams(window.location.search)).has('settings-updated')) {
        var cleanUrl = new URL(window.location.href);
        cleanUrl.searchParams.delete('settings-updated');
        window.history.replaceState(null, '', cleanUrl.pathname + cleanUrl.search + cleanUrl.hash);
    }

    /* ── Conditional rows ──────────────────────────────────────────────
     * A row tagged glse-dep-<option> is shown only while that option is on;
     * glse-dep-not-<option> is the inverse. Driven by the class so adding a
     * dependency needs no JS change - previously only two of the six pairs
     * were wired, so the rule the interface taught was true a third of the
     * time. */

    $('[class*="glse-dep-"]').each(function () {
        var $row  = $(this),
            deps  = String(this.className).match(/glse-dep-(?:not-)?[a-z_]+/g) || [];
        if (!deps.length) return;

        /* All dependencies must be satisfied - a row can hang off both its own
           option and the live_search master switch. */
        var watched = [];
        deps.forEach(function (cls) {
            var inverted = cls.indexOf('glse-dep-not-') === 0,
                key      = cls.replace(/^glse-dep-(not-)?/, ''),
                $source  = $('[name="glse_settings[' + key + ']"]').not('[type=hidden]');
            if ($source.length) watched.push({ $source: $source, inverted: inverted });
        });
        /* The stylesheet hides these rows until we place them, so one whose
           source is not on the page has to be revealed here or it would never
           come back. */
        if (!watched.length) { $row.show(); return; }

        var sync = function () {
            var visible = watched.every(function (w) {
                var on = w.$source.is(':checkbox') ? w.$source.is(':checked') : w.$source.val() === '1';
                return w.inverted ? !on : on;
            });
            $row.toggle(visible);
        };

        watched.forEach(function (w) { w.$source.on('change', sync); });
        sync();
    });

    /* ── Design preset: show/hide custom fields ── */

    var $presetCards = $('.glse-preset-card');
    /* Les rows de personnalisation ont la classe glse-design-row (via add_settings_field $args) */
    var $designRows  = $('.glse-design-row');

    function updatePreset() {
        var $checked = $presetCards.filter(function () {
            return $(this).find('input[type="radio"]').prop('checked');
        });
        var preset = $checked.find('input[type="radio"]').val() || 'custom';
        $presetCards.removeClass('glse-preset-card--active');
        $checked.addClass('glse-preset-card--active');
        if (preset === 'custom') {
            $designRows.show();
        } else {
            $designRows.hide();
        }
    }
    updatePreset();

    /* Card click: force radio check and update.
       Locked cards are skipped: letting the click through lights the card as
       active while the disabled radio is never submitted, so the screen shows
       one preset and the database stores another. */
    $presetCards.on('click', function () {
        var $radio = $(this).find('input[type="radio"]');
        if ($radio.is(':disabled')) return;
        $presetCards.find('input[type="radio"]').prop('checked', false);
        $radio.prop('checked', true);
        updatePreset();
    });

    /* ── Visual feedback on form submission ── */

    $('.glse-settings-form').on('submit', function () {
        var $btn = $('.glse-form-footer .button-primary');
        $btn.prop('disabled', true).html(
            '<svg xmlns="http://www.w3.org/2000/svg" width="15" height="15" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round" class="glse-spin"><path d="M21 12a9 9 0 1 1-6.219-8.56"/></svg> ' +
            (window.glseAdminL10n && glseAdminL10n.saving ? glseAdminL10n.saving : 'Saving\u2026')
        );
    });

    /* ── Analytics: submit via temporary form (avoids nested <form>) ── */

    /* Handed to the paid admin script, which needs it for CSV export and
       licence activation. One entry, and it stays that way. */
    function postViaForm(action, fields) {
        var $f = $('<form>', { method: 'post', action: action }).css('display', 'none');
        $.each(fields, function (name, value) {
            $f.append($('<input>', { type: 'hidden', name: name, value: value }));
        });
        $('body').append($f);
        $f.trigger('submit');
    }

    /* ── Fast search index ──
     * A plain POST, not AJAX: the ALTER can run for minutes on a large posts
     * table, and a request that times out mid-way would leave the merchant
     * unable to tell whether the index was built. */

    $(document).on('click', '.glse-fulltext-btn', function () {
        var $btn = $(this),
            msg  = $btn.data('confirm');

        if (msg && !confirm(msg)) return;

        $btn.prop('disabled', true).text($btn.data('op') === 'create' ? 'Building…' : 'Removing…');

        postViaForm($btn.data('action'), {
            _wpnonce: $btn.data('nonce'),
            _wp_http_referer: window.location.pathname + window.location.search,
            glse_fulltext_op: $btn.data('op')
        });
    });

    $(document).on('click', '.glse-clear-analytics-btn', function () {
        var $btn = $(this);
        if (!confirm($btn.data('confirm'))) return;
        postViaForm($btn.data('action'), {
            _wpnonce: $btn.data('nonce'),
            _wp_http_referer: window.location.pathname + window.location.search,
            glse_analytics_clear: '1'
        });
    });

    window.glseAdminCore = { postViaForm: postViaForm };
});
