// Focus management helpers for the centralised DialogHost (T33a). Small and
// dependency-free: capture/restore the trigger element's focus across a modal's
// lifetime, and trap Tab focus inside an open modal. Blazor calls these via
// JS interop (window.sbDialog.*); they are no-ops when there is nothing to act
// on, so prerender / loose-mode test calls do no harm.
(function () {
    'use strict';

    // CSS selector for elements that can receive keyboard focus within the modal.
    const FOCUSABLE =
        "a[href],button:not([disabled]),input:not([disabled])," +
        "select:not([disabled]),textarea:not([disabled])," +
        "[tabindex]:not([tabindex='-1'])";

    // The element that had focus when the most recent dialog opened. Module-level
    // so it survives between the capture (on open) and restore (on close) calls.
    let savedActiveElement = null;

    window.sbDialog = {
        // Stash the currently focused element so it can be restored on close.
        // Called BEFORE the modal steals focus.
        captureActiveElement: function () {
            savedActiveElement = document.activeElement;
        },

        // Return focus to the stashed element if it is still in the document,
        // then clear the stash so a later dialog starts fresh.
        restoreActiveElement: function () {
            const el = savedActiveElement;
            savedActiveElement = null;
            if (el && typeof el.focus === 'function' && el.isConnected) {
                el.focus();
            }
        },

        // Cycle focus within the modal: at the first focusable element a
        // Shift+Tab wraps to the last; at the last a Tab wraps to the first. In
        // both cases the default browser move (which would leave the modal) is
        // prevented. Anywhere else, the native Tab order applies untouched.
        focusTrap: function (modalEl, shiftKey) {
            if (!modalEl) return;
            const focusable = modalEl.querySelectorAll(FOCUSABLE);
            if (focusable.length === 0) return;

            const first = focusable[0];
            const last = focusable[focusable.length - 1];
            const active = document.activeElement;

            // Blazor interop does not hand us the DOM event, but window.event is
            // populated during the synchronous keydown dispatch on the engines we
            // target — guard the preventDefault so the wrap still works if it is
            // ever absent (the explicit .focus() override is the real trap).
            const evt = window.event;
            if (shiftKey && active === first) {
                last.focus();
                if (evt) evt.preventDefault();
            } else if (!shiftKey && active === last) {
                first.focus();
                if (evt) evt.preventDefault();
            }
        }
    };
})();
