/**
 * Audace — momentary scroll lock when a .is-style-slide reaches the top.
 *
 * On every scroll we check each slide's top-edge position against the line
 * where the site header (and admin bar, if any) ends. The moment a slide
 * crosses that line from below while the user is scrolling down, we freeze
 * page scroll for LOCK_MS so the user has to pause before continuing.
 *
 * No content is translated and no scroll budget is added; the freeze simply
 * pins the page at the current scroll position for the duration.
 */
(function () {
    'use strict';

    var LOCK_MS = 1200;
    // Trigger a bit before the slide's top reaches the header line so the
    // lock fires while there's still scroll momentum to cancel.
    var TRIGGER_EARLY = 300;
    // How long the snap-to-landing-position animation takes. Easing on top
    // so it glides in instead of jumping.
    var SNAP_MS = 500;

    function topOffset() {
        var adminBar = document.getElementById('wpadminbar');
        var header   = document.querySelector('.audace-site-header, .wp-block-template-part.site-header, header.wp-block-template-part, #masthead');
        var adminH   = adminBar ? adminBar.getBoundingClientRect().height : 0;
        var headerH  = header ? header.getBoundingClientRect().height : 0;
        return adminH + headerH;
    }

    var lastY = window.scrollY;
    var lockUntil = 0;
    var snapUntil = 0; // while true, keepY() lets the snap animation run
    var lockY = 0;
    var lockActive = false;
    var prev = new WeakMap();
    // Native scrollbar drags don't reliably fire mousedown on the page, so we
    // infer them from the absence of any other user-input event. If a scroll
    // happens without a recent wheel/key/touch, it's almost certainly a
    // scrollbar drag (or a programmatic scroll) — we let it pass through.
    var lastInputAt = 0;
    var INPUT_WINDOW_MS = 350;

    function markInput() { lastInputAt = Date.now(); }
    window.addEventListener('wheel',     markInput, { passive: true });
    window.addEventListener('keydown',   markInput, { passive: true });
    window.addEventListener('touchstart', markInput, { passive: true });
    window.addEventListener('touchmove',  markInput, { passive: true });

    function onScroll() {
        var y = window.scrollY;
        var down = y > lastY;
        var up   = y < lastY;
        lastY = y;
        // No recent wheel / key / touch → scrollbar drag or programmatic.
        if (Date.now() - lastInputAt > INPUT_WINDOW_MS) return;
        if (Date.now() < lockUntil) return;

        var top = topOffset();
        var bottomLine = window.innerHeight; // viewport bottom relative to rect
        var slides = document.querySelectorAll('.is-style-slide');
        for (var i = 0; i < slides.length; i++) {
            var s = slides[i];
            var r = s.getBoundingClientRect();
            var curTop    = r.top - top;          // distance from the header line
            var curBottom = r.top - bottomLine;   // distance from the viewport bottom
            var state = prev.get(s) || {};
            prev.set(s, { top: curTop, bottom: curBottom });

            // Scrolling DOWN: slide's top is approaching the header line from
            // below. Snap so the slide aligns with the header line, then lock.
            if (down && state.top !== undefined && state.top > TRIGGER_EARLY && curTop <= TRIGGER_EARLY) {
                startLock(y + curTop);
                break;
            }
            // Scrolling UP: slide's top is approaching the viewport bottom
            // from above (slide exiting downward). Snap so the slide sits at
            // the bottom of the viewport, then lock.
            if (up && state.bottom !== undefined && state.bottom < -TRIGGER_EARLY && curBottom >= -TRIGGER_EARLY) {
                startLock(y + curBottom);
                break;
            }
        }
    }

    function easeOutQuart(t) { return 1 - Math.pow(1 - t, 4); }

    function startLock(y) {
        // Lock covers both the snap animation and the hold afterwards, so
        // the user can't fight the animation mid-glide.
        var now = Date.now();
        snapUntil = now + SNAP_MS;
        lockUntil = now + SNAP_MS + LOCK_MS;
        lockY = y;
        // Smoothly animate to the exact landing position instead of jumping.
        var fromY = window.scrollY;
        var dy = y - fromY;
        if (dy !== 0) {
            var t0 = performance.now();
            (function step(now) {
                var k = Math.min(1, (now - t0) / SNAP_MS);
                var eased = easeOutQuart(k);
                window.scrollTo(0, fromY + dy * eased);
                if (k < 1) requestAnimationFrame(step);
            })(t0);
        }
        if (lockActive) return;
        lockActive = true;
        window.addEventListener('scroll', keepY, { passive: false });
        window.addEventListener('wheel',     blockDuringLock,  { passive: false, capture: true });
        window.addEventListener('touchmove', blockDuringLock,  { passive: false, capture: true });
        window.addEventListener('keydown',   blockScrollKeys,  { capture: true });
        // Belt and braces: force the scroll position every animation frame
        // so inertia / momentum scroll can't sneak past between scroll events.
        pinRaf = requestAnimationFrame(pinLoop);
        setTimeout(releaseLock, SNAP_MS + LOCK_MS);
    }

    var pinRaf = 0;
    var SCROLL_KEYS = { 32:1, 33:1, 34:1, 35:1, 36:1, 37:1, 38:1, 39:1, 40:1 }; // space, pgup, pgdn, end, home, arrows
    function pinLoop() {
        pinRaf = 0;
        var now = Date.now();
        if (now >= lockUntil) return;
        if (now >= snapUntil && window.scrollY !== lockY) window.scrollTo(0, lockY);
        pinRaf = requestAnimationFrame(pinLoop);
    }
    function blockScrollKeys(e) {
        if (Date.now() >= lockUntil) return;
        if (SCROLL_KEYS[e.keyCode]) {
            e.preventDefault();
            e.stopPropagation();
        }
    }

    function keepY() {
        var now = Date.now();
        if (now >= lockUntil) return;
        // Let the snap animation progress; only clamp once it's finished.
        if (now < snapUntil) return;
        if (window.scrollY !== lockY) window.scrollTo(0, lockY);
    }
    function blockDuringLock(e) {
        if (Date.now() < lockUntil) e.preventDefault();
    }
    function releaseLock() {
        lockActive = false;
        if (pinRaf) { cancelAnimationFrame(pinRaf); pinRaf = 0; }
        window.removeEventListener('scroll', keepY);
        window.removeEventListener('wheel',     blockDuringLock,  { capture: true });
        window.removeEventListener('touchmove', blockDuringLock,  { capture: true });
        window.removeEventListener('keydown',   blockScrollKeys,  { capture: true });
    }

    function init() {
        // Seed the initial positions so we don't falsely trigger on page load.
        var slides = document.querySelectorAll('.is-style-slide');
        var top = topOffset();
        slides.forEach(function (s) {
            prev.set(s, s.getBoundingClientRect().top - top);
        });
        window.addEventListener('scroll', onScroll, { passive: true });
    }

    if (document.readyState === 'loading') {
        document.addEventListener('DOMContentLoaded', init);
    } else {
        init();
    }
})();
