// Full-viewport Overlay component (mobile). Distinct from the .modal dialog:
// this hosts a whole rail (the folder tree or the right-rail widgets/TOC) at
// full screen with its own scroll and a top-right close control. It reuses the
// low-level focus/Escape/bfcache patterns from modal.js rather than that
// component's panel chrome.
//
// openOverlay(node, opts) MOVES `node` (an existing rail <aside>) into the
// overlay body and restores it to its original DOM position on close, so the
// rail keeps its state (expanded tree folders, rendered TOC). Only one overlay
// is open at a time.
(function () {
    var overlay = null;
    var bodyEl = null;
    var closeBtn = null;
    var hosted = null;      // the moved node
    var placeholder = null; // marks where to restore it
    var prevFocus = null;
    var onKeydown = null;
    var onCloseCb = null;   // opts.onClose of the currently hosted node

    function build() {
        overlay = document.createElement('div');
        overlay.className = 'overlay';
        overlay.setAttribute('role', 'dialog');
        overlay.setAttribute('aria-modal', 'true');

        var bar = document.createElement('div');
        bar.className = 'overlay-bar';

        closeBtn = document.createElement('button');
        closeBtn.type = 'button';
        closeBtn.className = 'btn btn-fab overlay-close';
        closeBtn.title = 'Close';
        closeBtn.setAttribute('aria-label', 'Close');
        closeBtn.textContent = '×';
        closeBtn.addEventListener('click', close);
        bar.appendChild(closeBtn);

        bodyEl = document.createElement('div');
        bodyEl.className = 'overlay-body';
        // Any navigation or anchor activation inside a rail dismisses the
        // overlay: tree/calendar links navigate away, TOC links scroll the
        // page underneath — either way the user should see the result, and
        // closing synchronously (before navigation) avoids a bfcache snapshot
        // that would restore the overlay open on back-nav.
        bodyEl.addEventListener('click', function (e) {
            if (e.target.closest('a')) close();
        });

        overlay.appendChild(bar);
        overlay.appendChild(bodyEl);
    }

    function open(node, opts) {
        if (overlay && overlay.parentNode) close();
        if (!overlay) build();
        opts = opts || {};

        prevFocus = document.activeElement;
        onCloseCb = typeof opts.onClose === 'function' ? opts.onClose : null;
        hosted = node;
        placeholder = document.createComment('overlay-slot');
        node.parentNode.insertBefore(placeholder, node);
        bodyEl.appendChild(node);

        document.body.appendChild(overlay);
        overlay.classList.add('is-open');

        onKeydown = function (e) {
            if (e.key === 'Escape') { e.preventDefault(); close(); }
        };
        document.addEventListener('keydown', onKeydown);

        setTimeout(function () { closeBtn.focus(); }, 0);

        if (typeof opts.onOpen === 'function') opts.onOpen();
        return { close: close };
    }

    function close() {
        if (!overlay || !overlay.parentNode) return;
        if (onKeydown) {
            document.removeEventListener('keydown', onKeydown);
            onKeydown = null;
        }
        // Restore the hosted rail to its original spot in the shell.
        if (hosted && placeholder && placeholder.parentNode) {
            placeholder.parentNode.insertBefore(hosted, placeholder);
            placeholder.parentNode.removeChild(placeholder);
        }
        hosted = null;
        placeholder = null;
        overlay.classList.remove('is-open');
        overlay.parentNode.removeChild(overlay);

        var toRestore = prevFocus;
        prevFocus = null;
        if (toRestore && toRestore.focus) {
            try { toRestore.focus(); } catch (e) {}
        }

        // Fires after the node is back in its original spot, so the callback
        // sees the final DOM.
        var cb = onCloseCb;
        onCloseCb = null;
        if (cb) cb();
    }

    // Belt-and-suspenders bfcache guard: force the overlay closed (restoring
    // the rail) if the page is being hidden while it is still open.
    window.addEventListener('pagehide', close);

    window.openOverlay = open;
    window.closeOverlay = close;
})();
