/**
 * Sentinel Onboarding (Quick Setup) front-end behaviour.
 *
 * Scope:
 *   - Eye follows pointer for every .sentinel-logo-eye on the page
 *     (same selector and math as the GetSentinel marketing theme).
 *   - Modal open/close, step navigation, profile selection, ESC handling.
 *
 * Phase 2: AJAX preview + apply (saves sentinel_log_management), skip/dismiss.
 */
(function () {
    'use strict';

    var settings = (typeof window.sentinelOnboardingData === 'object' && window.sentinelOnboardingData) || {};
    var i18n = settings.i18n || {};
    var reducedMotion = window.matchMedia && window.matchMedia('(prefers-reduced-motion: reduce)').matches;

    /* ----------------------------------------------------------------- */
    /* Eye follow                                                        */
    /* ----------------------------------------------------------------- */
    var eyeGroups = [];
    function refreshEyeGroups() {
        eyeGroups = Array.prototype.slice.call(document.querySelectorAll('.sentinel-logo-eye'));
    }
    refreshEyeGroups();

    function updateEyes(pointerX, pointerY) {
        if (reducedMotion) {
            return;
        }
        for (var i = 0; i < eyeGroups.length; i++) {
            var group = eyeGroups[i];
            var svg = group.ownerSVGElement;
            if (!svg) {
                continue;
            }
            var rect = svg.getBoundingClientRect();
            if (rect.width === 0 || rect.height === 0) {
                continue;
            }
            var cx = rect.left + rect.width * 0.5;
            var cy = rect.top + rect.height * 0.5;
            var dx = pointerX - cx;
            var dy = pointerY - cy;
            var angle = Math.atan2(dy, dx);
            // Match the marketing theme: clamp to a small max move, with
            // distance-based easing for a calm, deliberate motion.
            var distance = Math.min(Math.hypot(dx, dy) / 200, 1);
            var eased = distance * distance;
            var maxMove = 6;
            var moveX = Math.cos(angle) * maxMove * eased;
            var moveY = Math.sin(angle) * maxMove * eased;
            group.style.transform = 'translate(' + moveX.toFixed(2) + 'px, ' + moveY.toFixed(2) + 'px)';
        }
    }

    function resetEyes() {
        for (var i = 0; i < eyeGroups.length; i++) {
            eyeGroups[i].style.transform = 'translate(0px, 0px)';
        }
    }

    document.addEventListener('mousemove', function (e) {
        updateEyes(e.clientX, e.clientY);
    }, { passive: true });
    document.addEventListener('mouseleave', resetEyes);

    /* ----------------------------------------------------------------- */
    /* Modal: open / close / step navigation                             */
    /* ----------------------------------------------------------------- */
    var modal = document.getElementById('sentinel-onboarding-modal');
    if (!modal) {
        return; // Modal not on this screen, eye-follow still wired.
    }

    var bodyEl = modal.querySelector('.sentinel-onboarding__body');
    var successEl = document.getElementById('sentinel-onboarding-success');
    var counterEl = modal.querySelector('.sentinel-onboarding__step-counter');
    var stepBarEl = modal.querySelector('.sentinel-onboarding__step-bar');
    var backBtn = modal.querySelector('[data-sentinel-back]');
    var nextBtn = modal.querySelector('[data-sentinel-next]');
    var closeBtn = modal.querySelector('[data-sentinel-close]');
    var lastFocus = null;
    var currentStep = 0;
    var selectedProfileKey = 'recommended';
    var selectedPrivacyKey = 'standard';
    /** Remembers Plus-step input when navigating Back so the field is restored. Not sent to apply. */
    var storedLicence = '';
    var plusLicenceState = 'idle'; // idle | loading | ok | error
    var licenceValidateTimer = null;
    var licenceDebounceMs = 600;

    /**
     * Use the browser's current scheme/origin for admin-ajax when the host matches.
     * Stops mixed-content blocking (HTTPS admin page + HTTP ajaxurl from PHP) → "Failed to fetch".
     */
    function resolveAdminAjaxUrl(localized) {
        var fallback =
            (typeof window.ajaxurl === 'string' && window.ajaxurl)
                ? window.ajaxurl
                : (localized || '');
        if (!fallback) {
            return fallback;
        }
        try {
            var page = window.location;
            var u = new URL(fallback, page.href);
            if (u.hostname !== page.hostname) {
                return fallback;
            }
            return page.origin + u.pathname + (u.search || '');
        } catch (e) {
            return fallback;
        }
    }

    var adminAjaxUrl = resolveAdminAjaxUrl(settings.ajaxurl);

    /**
     * Step definitions. Markup is rendered with a simple template helper.
     * Server-side strings are i18n-ed by PHP and exposed via
     * sentinelOnboardingData.i18n.
     */
    var steps = [
        {
            key: 'welcome',
            hero: 'hero-welcome',
            title: i18n.welcome_title || 'Welcome',
            lede: i18n.welcome_lede || 'Sentinel is already logging. The next four screens tune what you actually feel.',
            body:
                '<p>' + (i18n.welcome_body || 'Each screen changes a small set of options. The last one shows the diff before anything is saved.') + '</p>' +
                '<details><summary>' + (i18n.welcome_audience_summary || 'Who is this for?') + '</summary>' +
                '<p style="margin-top:8px;">' + (i18n.welcome_audience_body || 'Site managers, developers, and agencies who want a clear audit trail and calm alerting.') + '</p>' +
                '</details>',
        },
        {
            key: 'plus',
            hero: 'hero-plus',
            title: i18n.plus_title || 'Sentinel+ (optional)',
            lede: i18n.plus_lede || 'Paste a licence key to unlock Sentinel+ here. Leave it empty to carry on free.',
            body:
                '<p class="sentinel-onboarding__plus-status" data-sentinel-plus-status hidden></p>' +
                '<label class="sentinel-onboarding__label" for="sentinel-qs-licence">' + (i18n.plus_label || 'Licence key') + '</label>' +
                '<input id="sentinel-qs-licence" type="text" autocomplete="off" spellcheck="false" placeholder="' + (i18n.plus_placeholder || 'optional. leave empty to continue free.') + '" />' +
                '<div id="sentinel-qs-licence-feedback" class="sentinel-onboarding__licence-feedback" role="status" aria-live="polite"></div>' +
                '<div class="sentinel-onboarding__hint">' + (i18n.plus_hint || 'No key yet?') + ' <a href="https://getsentinel.dev/plus/" target="_blank" rel="noopener">' + (i18n.plus_hint_link || 'View Sentinel+ pricing') + '</a>.</div>' +
                '<aside class="sentinel-onboarding__plus-promo">' +
                '<span class="sentinel-onboarding__plus-badge">SENTINEL+</span>' +
                '<h4>' + (i18n.plus_promo_title || 'Built for shops, agencies, and security work') + '</h4>' +
                '<p>' + (i18n.plus_promo_body || 'Incident detection with response modes, deeper file monitoring, memory leak detection, Woo and Multisite integrations. Nothing in setup is blocked behind a key.') + '</p>' +
                '<div class="sentinel-onboarding__plus-actions">' +
                '<a class="sentinel-qs-btn sentinel-qs-btn--plus" href="https://getsentinel.dev/plus/" target="_blank" rel="noopener">' + (i18n.plus_cta_primary || 'Get Sentinel+') + '</a>' +
                '<a class="sentinel-onboarding__link-purple" href="https://getsentinel.dev/plus/#features" target="_blank" rel="noopener">' + (i18n.plus_cta_secondary || 'See feature list') + '</a>' +
                '</div></aside>',
        },
        {
            key: 'profile',
            hero: 'hero-profile',
            title: i18n.profile_title || 'Pick a style',
            lede: i18n.profile_lede || 'Each style touches a small set of options. The review step shows the diff.',
            body:
                '<div class="sentinel-onboarding__profile-grid" data-sentinel-profile-grid>' +
                renderProfile('recommended', i18n.profile_recommended_title || 'Recommended', i18n.profile_recommended_body || 'Email on critical and security events. Ninety day anonymise.', true) +
                renderProfile('quiet', i18n.profile_quiet_title || 'Quiet Logger', i18n.profile_quiet_body || 'Digest first. Less email noise.', false) +
                renderProfile('security', i18n.profile_security_title || 'Security Watch', i18n.profile_security_body || 'Thirty day retention. Sentinel+ steps unlock with a licence.', false) +
                renderProfile('performance', i18n.profile_performance_title || 'Performance Conscious', i18n.profile_performance_body || 'Batched logging. Calmer rate limit behaviour.', false) +
                '</div>',
        },
        {
            key: 'privacy',
            hero: 'hero-privacy',
            title: i18n.privacy_title || 'Privacy level',
            lede: i18n.privacy_lede || 'These map onto the privacy options Sentinel already uses.',
            body:
                '<div class="sentinel-onboarding__profile-grid" data-sentinel-profile-grid>' +
                renderProfile('standard', i18n.privacy_standard_title || 'Standard', i18n.privacy_standard_body || 'IPs logged. Anonymise after ninety days.', true) +
                renderProfile('privacy_conscious', i18n.privacy_conscious_title || 'Privacy conscious', i18n.privacy_conscious_body || 'IPs logged. Anonymise after thirty days. RTBF and export shortcodes available.', false) +
                renderProfile('minimal', i18n.privacy_minimal_title || 'Minimal personal data', i18n.privacy_minimal_body || 'No IP logging. Anonymise after thirty days. RTBF and export available.', false) +
                '</div>',
        },
        {
            key: 'review',
            hero: 'hero-review',
            title: i18n.review_title || 'Review and confirm',
            lede: i18n.review_lede || 'Only the keys below change. Everything else stays exactly as it is.',
            body: '<table class="sentinel-onboarding__diff"><thead><tr><th>' +
                (i18n.review_col_setting || 'Setting') + '</th><th>' +
                (i18n.review_col_now || 'Now') + '</th><th>' +
                (i18n.review_col_after || 'After') + '</th></tr></thead><tbody data-sentinel-diff></tbody></table>',
        },
    ];

    function normalizeLicenceInput(str) {
        return String(str).trim().replace(/\s+/g, '').toUpperCase();
    }

    function licenceShapeComplete(normalized) {
        return /^SEN-[A-Z0-9]{4}-[A-Z0-9]{4}-[A-Z0-9]{4}-[A-Z0-9]{4}$/.test(normalized);
    }

    function showGlobalNotice(msg) {
        var el = document.getElementById('sentinel-onboarding-global-notice');
        if (!el) {
            return;
        }
        el.textContent = msg || '';
        el.hidden = !msg;
    }

    function showAdminNoticeError(msg) {
        if (!msg) {
            return;
        }
        var wrap = document.querySelector('#wpbody-content .wrap');
        if (!wrap) {
            window.alert(msg);
            return;
        }
        var n = document.createElement('div');
        n.className = 'notice notice-error';
        n.setAttribute('role', 'alert');
        var p = document.createElement('p');
        p.textContent = msg;
        n.appendChild(p);
        wrap.insertBefore(n, wrap.firstChild);
        window.scrollTo({ top: 0, behavior: 'smooth' });
    }

    function setLicenceFeedback(text, kind) {
        var el = document.getElementById('sentinel-qs-licence-feedback');
        if (!el) {
            return;
        }
        el.className = 'sentinel-onboarding__licence-feedback';
        if (kind) {
            el.classList.add('is--' + kind);
        }
        el.textContent = text || '';
    }

    function updatePlusContinueEnabled() {
        if (steps[currentStep].key !== 'plus') {
            nextBtn.disabled = false;
            return;
        }
        var input = document.getElementById('sentinel-qs-licence');
        var v = input ? normalizeLicenceInput(input.value) : '';
        if (v === '') {
            nextBtn.disabled = false;
            return;
        }
        if (!licenceShapeComplete(v)) {
            nextBtn.disabled = true;
            return;
        }
        if (plusLicenceState === 'loading') {
            nextBtn.disabled = true;
            return;
        }
        nextBtn.disabled = (plusLicenceState !== 'ok');
    }

    function validateLicenceNow() {
        var input = document.getElementById('sentinel-qs-licence');
        if (!input) {
            return;
        }
        var norm = normalizeLicenceInput(input.value);
        if (norm === '') {
            plusLicenceState = 'idle';
            setLicenceFeedback('', '');
            updatePlusContinueEnabled();
            return;
        }
        if (!licenceShapeComplete(norm)) {
            plusLicenceState = 'idle';
            setLicenceFeedback(i18n.plus_hint_shape || '', 'info');
            updatePlusContinueEnabled();
            return;
        }
        plusLicenceState = 'loading';
        setLicenceFeedback(i18n.plus_validating || '…', 'loading');
        updatePlusContinueEnabled();

        onboardingAjax('sentinel_onboarding_validate_licence', { licence: norm }).then(function (res) {
            if (steps[currentStep].key !== 'plus') {
                return;
            }
            if (normalizeLicenceInput(input.value) !== norm) {
                return;
            }
            if (res && res.success) {
                plusLicenceState = 'ok';
                if (res.data && res.data.normalized) {
                    input.value = res.data.normalized;
                }
                setLicenceFeedback(i18n.plus_licence_ok || '', 'success');
            } else {
                plusLicenceState = 'error';
                var msg = (res && res.data && res.data.message)
                    ? res.data.message
                    : (i18n.ajax_error_generic || '');
                setLicenceFeedback(msg, 'error');
            }
            updatePlusContinueEnabled();
        }).catch(function (err) {
            if (steps[currentStep].key !== 'plus') {
                return;
            }
            plusLicenceState = 'error';
            var msg = (err && err.message) ? err.message : (i18n.ajax_error_generic || '');
            setLicenceFeedback(msg, 'error');
            updatePlusContinueEnabled();
        });
    }

    function scheduleLicenceValidate() {
        clearTimeout(licenceValidateTimer);
        licenceValidateTimer = setTimeout(function () {
            licenceValidateTimer = null;
            validateLicenceNow();
        }, licenceDebounceMs);
    }

    function onPlusLicenceInput() {
        var input = document.getElementById('sentinel-qs-licence');
        if (!input) {
            return;
        }
        var norm = normalizeLicenceInput(input.value);
        if (norm === '') {
            clearTimeout(licenceValidateTimer);
            plusLicenceState = 'idle';
            setLicenceFeedback('', '');
            updatePlusContinueEnabled();
            return;
        }
        if (!licenceShapeComplete(norm)) {
            clearTimeout(licenceValidateTimer);
            plusLicenceState = 'idle';
            setLicenceFeedback(i18n.plus_hint_shape || '', 'info');
            updatePlusContinueEnabled();
            return;
        }
        scheduleLicenceValidate();
    }

    function bindPlusLicenceInteractions() {
        var input = document.getElementById('sentinel-qs-licence');
        if (!input) {
            return;
        }
        input.addEventListener('input', onPlusLicenceInput);
        input.addEventListener('paste', function () {
            window.setTimeout(onPlusLicenceInput, 0);
        });
    }

    function onboardingAjax(action, extraFields) {
        var fd = new FormData();
        fd.append('action', action);
        fd.append('nonce', settings.nonce);
        if (extraFields) {
            Object.keys(extraFields).forEach(function (k) {
                fd.append(k, extraFields[k]);
            });
        }
        return fetch(adminAjaxUrl || settings.ajaxurl, {
            method: 'POST',
            body: fd,
            credentials: 'same-origin',
        }).then(function (r) {
            return r.text().then(function (text) {
                var json;
                try {
                    json = text ? JSON.parse(text) : {};
                } catch (ignore) {
                    var snippet = (text || '').replace(/<[^>]+>/g, ' ').replace(/\s+/g, ' ').trim();
                    if (snippet.length > 200) {
                        snippet = snippet.substring(0, 200) + '…';
                    }
                    return Promise.reject(new Error(snippet || ('Unable to read server response (HTTP ' + r.status + ').')));
                }
                return json;
            });
        });
    }

    function loadReviewDiff() {
        var tbody = bodyEl.querySelector('[data-sentinel-diff]');
        if (!tbody) {
            return;
        }
        tbody.innerHTML = '<tr><td colspan="3">' +
            escapeHtml(i18n.review_loading || '') + '</td></tr>';
        onboardingAjax('sentinel_onboarding_preview', {
            profile: selectedProfileKey,
            privacy: selectedPrivacyKey,
        }).then(function (res) {
            if (!res || !res.success) {
                tbody.innerHTML = '<tr><td colspan="3">' +
                    escapeHtml(i18n.ajax_error_generic || '') + '</td></tr>';
                return;
            }
            var rows = res.data && res.data.diff ? res.data.diff : [];
            paintDiffRows(rows);
        }).catch(function () {
            tbody.innerHTML = '<tr><td colspan="3">' +
                escapeHtml(i18n.ajax_error_generic || '') + '</td></tr>';
        });
    }

    function paintDiffRows(rows) {
        var tbody = bodyEl.querySelector('[data-sentinel-diff]');
        if (!tbody) {
            return;
        }
        if (!rows.length) {
            tbody.innerHTML = '<tr><td colspan="3"><em>' +
                escapeHtml(i18n.ajax_preview_empty || '') + '</em></td></tr>';
            return;
        }
        tbody.innerHTML = rows.map(function (r) {
            var settingLabel = escapeHtml(reviewPrettyLabel(r.key));
            var nowCell = escapeHtml(formatReviewValue(r.key, r.now));
            var afterFmt = formatReviewValue(r.key, r.after);
            var afterCell = '<strong>' + escapeHtml(afterFmt) + '</strong>';
            return '<tr><td>' + settingLabel + '</td><td>' + nowCell + '</td><td>' + afterCell + '</td></tr>';
        }).join('');
    }

    function restoreSelections(stepKey) {
        if (stepKey !== 'profile' && stepKey !== 'privacy') {
            return;
        }
        var want = stepKey === 'profile' ? selectedProfileKey : selectedPrivacyKey;
        var grid = bodyEl.querySelector('[data-sentinel-profile-grid]');
        if (!grid) {
            return;
        }
        var cards = grid.querySelectorAll('[data-sentinel-profile]');
        var matched = null;
        cards.forEach(function (card) {
            if (card.getAttribute('data-sentinel-profile') === want) {
                matched = card;
            }
        });
        if (matched) {
            selectProfile(matched, cards, true);
        }
    }

    function renderProfile(key, title, body, selected) {
        return '<article class="sentinel-onboarding__profile' + (selected ? ' is-selected' : '') + '" data-sentinel-profile="' + key + '" tabindex="0" role="button" aria-pressed="' + (selected ? 'true' : 'false') + '">' +
            '<h4>' + title + ' <span class="sentinel-onboarding__pick-state" aria-hidden="true"></span></h4>' +
            '<p>' + body + '</p>' +
            '</article>';
    }

    function render() {
        var step = steps[currentStep];
        bodyEl.innerHTML =
            '<div class="sentinel-onboarding__step-hero" aria-hidden="true">' +
                '<svg class="sentinel-onboarding__step-hero-svg" width="240" height="110" viewBox="0 0 240 110" preserveAspectRatio="xMidYMid meet" focusable="false"><use href="#' + step.hero + '"></use></svg>' +
            '</div>' +
            '<h3>' + step.title + '</h3>' +
            '<p class="lede">' + step.lede + '</p>' +
            step.body;

        counterEl.textContent = (i18n.step_counter || 'Step %1$s of %2$s')
            .replace('%1$s', (currentStep + 1).toString())
            .replace('%2$s', steps.length.toString());

        var bars = stepBarEl.children;
        for (var i = 0; i < bars.length; i++) {
            bars[i].classList.remove('is-done', 'is-active');
            if (i < currentStep) { bars[i].classList.add('is-done'); }
            if (i === currentStep) { bars[i].classList.add('is-active'); }
        }

        backBtn.disabled = currentStep === 0;
        nextBtn.textContent = (currentStep === steps.length - 1)
            ? (i18n.btn_apply || 'Apply and finish')
            : (i18n.btn_continue || 'Continue');

        bindStepInteractions();
        restoreSelections(step.key);
        if (step.key === 'plus') {
            var statusEl = bodyEl.querySelector('[data-sentinel-plus-status]');
            if (statusEl) {
                if (settings.is_premium_active || settings.has_stored_licence) {
                    statusEl.hidden = false;
                    statusEl.textContent = i18n.plus_status_active || '';
                } else {
                    statusEl.hidden = true;
                    statusEl.textContent = '';
                }
            }
            var licenceInput = document.getElementById('sentinel-qs-licence');
            if (licenceInput) {
                licenceInput.value = storedLicence;
            }
            bindPlusLicenceInteractions();
            plusLicenceState = 'idle';
            setLicenceFeedback('', '');
            onPlusLicenceInput();
        } else {
            clearTimeout(licenceValidateTimer);
            licenceValidateTimer = null;
        }
        if (step.key === 'review') {
            loadReviewDiff();
        }
        refreshEyeGroups(); // Catch hero illustration eyes if present.
        updatePlusContinueEnabled();
    }

    function bindStepInteractions() {
        var grid = bodyEl.querySelector('[data-sentinel-profile-grid]');
        if (grid) {
            var cards = grid.querySelectorAll('[data-sentinel-profile]');
            cards.forEach(function (card) {
                card.addEventListener('click', function () { selectProfile(card, cards, false); });
                card.addEventListener('keydown', function (e) {
                    if (e.key === 'Enter' || e.key === ' ') {
                        e.preventDefault();
                        selectProfile(card, cards, false);
                    }
                });
            });
        }
    }

    function selectProfile(card, all, isRestoring) {
        all.forEach(function (c) {
            c.classList.remove('is-selected');
            c.setAttribute('aria-pressed', 'false');
        });
        card.classList.add('is-selected');
        card.setAttribute('aria-pressed', 'true');
        if (isRestoring === true) {
            return;
        }
        var sk = steps[currentStep].key;
        var pk = card.getAttribute('data-sentinel-profile');
        if (sk === 'profile') {
            selectedProfileKey = pk;
        }
        if (sk === 'privacy') {
            selectedPrivacyKey = pk;
        }
    }

    function escapeHtml(str) {
        if (str === null || str === undefined) {
            return '';
        }
        var d = document.createElement('div');
        d.textContent = String(str);
        return d.innerHTML;
    }

    function reviewPrettyLabel(key) {
        var m = i18n.review_setting_labels || {};
        return m[key] || key;
    }

    function formatReviewValue(settingKey, raw) {
        var rawStr = raw === null || raw === undefined ? '' : String(raw);
        var toggleSetting = (/^sentinel_email_/.test(settingKey))
            || settingKey === 'log_ip_addresses'
            || settingKey === 'batch_logging_enabled'
            || settingKey === 'right_to_be_forgotten'
            || settingKey === 'data_portability';
        if (toggleSetting) {
            var t = i18n.review_vals_toggle || {};
            var k = rawStr.toLowerCase();
            if (Object.prototype.hasOwnProperty.call(t, rawStr)) {
                return t[rawStr];
            }
            if (Object.prototype.hasOwnProperty.call(t, k)) {
                return t[k];
            }
            return rawStr;
        }
        var anonymize = i18n.review_vals_anonymize_schedule || {};
        if (settingKey === 'anonymize_schedule' && anonymize[rawStr]) {
            return anonymize[rawStr];
        }
        var rate = i18n.review_vals_rate_limit_behavior || {};
        if (settingKey === 'rate_limit_behavior' && rate[rawStr]) {
            return rate[rawStr];
        }
        if (settingKey === 'excluded_user_roles') {
            var roleMap = i18n.review_vals_roles || {};
            return rawStr.split(',').map(function (s) {
                var slug = s.trim();
                if (!slug) {
                    return '';
                }
                if (roleMap[slug]) {
                    return roleMap[slug];
                }
                return slug.charAt(0).toUpperCase() + slug.slice(1).toLowerCase().replace(/_/g, ' ');
            }).filter(Boolean).join(', ');
        }
        return rawStr;
    }

    function hideApplySuccessScreen() {
        if (successEl) {
            successEl.hidden = true;
        }
        modal.classList.remove('sentinel-onboarding--apply-success');
        if (bodyEl) {
            bodyEl.style.display = '';
        }
    }

    function showApplySuccessScreen() {
        if (successEl) {
            var t = successEl.querySelector('.sentinel-onboarding__success-title');
            var lede = successEl.querySelector('.sentinel-onboarding__success-lede');
            var hint = successEl.querySelector('.sentinel-onboarding__success-hint');
            if (t) {
                t.textContent = i18n.success_title || 'You\'re all set!';
            }
            if (lede) {
                lede.textContent = i18n.success_lede || '';
            }
            if (hint) {
                hint.textContent = i18n.success_refresh_hint || '';
            }
            successEl.hidden = false;
        }
        modal.classList.add('sentinel-onboarding--apply-success');
        if (bodyEl) {
            bodyEl.style.display = 'none';
        }
    }

    function applyAndFinish() {
        var origLabel = nextBtn.textContent;
        nextBtn.disabled = true;
        nextBtn.textContent = i18n.btn_applying || '…';
        showGlobalNotice('');
        onboardingAjax('sentinel_onboarding_apply', {
            profile: selectedProfileKey,
            privacy: selectedPrivacyKey,
        }).then(function (res) {
            nextBtn.disabled = false;
            nextBtn.textContent = origLabel;
            if (!res || !res.success) {
                var msg = (res && res.data && res.data.message)
                    ? res.data.message
                    : (i18n.ajax_error_generic || '');
                showGlobalNotice(msg);
                return;
            }
            showApplySuccessScreen();
            window.setTimeout(function () {
                window.location.reload();
            }, 2800);
        }).catch(function () {
            nextBtn.disabled = false;
            nextBtn.textContent = origLabel;
            showGlobalNotice(i18n.ajax_error_generic || '');
        });
    }

    function openModal(stepKey) {
        hideApplySuccessScreen();
        selectedProfileKey = 'recommended';
        selectedPrivacyKey = 'standard';
        storedLicence = '';
        plusLicenceState = 'idle';
        clearTimeout(licenceValidateTimer);
        licenceValidateTimer = null;
        showGlobalNotice('');
        var idx = steps.findIndex(function (s) { return s.key === stepKey; });
        currentStep = idx >= 0 ? idx : 0;
        lastFocus = document.activeElement;
        render();
        modal.classList.add('is-open');
        document.body.style.overflow = 'hidden';
        // Move focus to the close button so keyboard users land in the modal.
        if (closeBtn && typeof closeBtn.focus === 'function') {
            window.setTimeout(function () { closeBtn.focus(); }, 30);
        }
    }

    function closeModal() {
        modal.classList.remove('is-open');
        document.body.style.overflow = '';
        if (lastFocus && typeof lastFocus.focus === 'function') {
            lastFocus.focus();
        }
    }

    nextBtn.addEventListener('click', function () {
        if (steps[currentStep].key === 'plus') {
            var ln = document.getElementById('sentinel-qs-licence');
            if (ln) {
                storedLicence = ln.value.trim();
            }
        }
        if (currentStep < steps.length - 1) {
            currentStep++;
            render();
            return;
        }
        applyAndFinish();
    });
    backBtn.addEventListener('click', function () {
        if (currentStep > 0) {
            currentStep--;
            render();
        }
    });
    closeBtn.addEventListener('click', closeModal);
    modal.addEventListener('click', function (e) {
        if (modal.classList.contains('sentinel-onboarding--apply-success')) {
            return;
        }
        if (e.target === modal) {
            closeModal();
        }
    });
    document.addEventListener('keydown', function (e) {
        if (e.key === 'Escape' && modal.classList.contains('is-open')) {
            if (modal.classList.contains('sentinel-onboarding--apply-success')) {
                return;
            }
            closeModal();
        }
    });

    // Triggers on the page that open the modal.
    document.querySelectorAll('[data-sentinel-open]').forEach(function (el) {
        el.addEventListener('click', function (e) {
            e.preventDefault();
            openModal(el.getAttribute('data-sentinel-open') || 'welcome');
        });
    });

    document.querySelectorAll('[data-sentinel-qs-skip]').forEach(function (btn) {
        btn.addEventListener('click', function (e) {
            e.preventDefault();
            showGlobalNotice('');
            onboardingAjax('sentinel_onboarding_skip', {}).then(function (res) {
                if (res && res.success) {
                    window.location.reload();
                    return;
                }
                var msg = (res && res.data && res.data.message)
                    ? res.data.message
                    : (i18n.ajax_error_generic || '');
                showAdminNoticeError(msg);
            }).catch(function () {
                showAdminNoticeError(i18n.ajax_error_generic || '');
            });
        });
    });

    // Auto-open on page load if pending and admin asked us to (Phase 2 behaviour);
    // for Phase 1 we leave this to explicit clicks only.
    if (settings.auto_open && settings.auto_open === 'welcome') {
        openModal('welcome');
    }
})();
