jQuery(function ($){'use strict';// ---------- Config ---------- var REQUIRED_SECONDS=270;// 4.5 minutes var VIDEO_THRESHOLD=0.9;// 90% of the video must be watched var SAVE_EVERY_MS=3000;// throttle localStorage writes from timeupdate var MAX_TICK_SECONDS=2;;function store(key,val){try{if (val===undefined){var v=localStorage.getItem(key);return v===null ? (memStore[key]===undefined ? null:memStore[key]):v}localStorage.setItem(key,val)}catch (e){if (val !==undefined){memStore[key]=String(val)}else{return memStore[key]===undefined ? null:memStore[key]}}}// ---------- Best-effort user id so shared devices don't share progress ----------
    function getUserId() {
        try {
            var o = window._tutorobject;
            if (o && o.current_user && o.current_user.data && o.current_user.data.ID) {
                return String(o.current_user.data.ID);
            }
        } catch (e) {}
        return 'u';
    }

    // ---------- One-time styles for the timer bar ----------
    if (!document.getElementById('lesson-timer-css')) {
        var css = document.createElement('style');
        css.id = 'lesson-timer-css';
        css.textContent =
            '#lesson-timer{background:#1e293b;color:#fff;padding:12px 20px;text-align:center;' +
            'font-family:-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,sans-serif;font-size:14px;' +
            'font-weight:600;border-radius:6px;margin-bottom:20px;display:flex;align-items:center;' +
            'justify-content:space-between;box-shadow:0 4px 12px rgb(0 0 0 / .15);gap:8px}' +
            '#lesson-timer .lt-exit{color:#94a3b8;text-decoration:none;font-size:13px;border:1px solid #475569;' +
            'padding:4px 10px;border-radius:4px;background:#0f172a;white-space:nowrap}' +
            '#lesson-timer .lt-msg{flex-grow:1;text-align:center}' +
            '#lesson-timer .lt-spacer{width:80px}' +
            '#lesson-timer .lt-ok{color:#38bdf8}#lesson-timer .lt-warn{color:#fbbf24}' +
            '@media(max-width:600px){#lesson-timer .lt-spacer{display:none}}';
        document.head.appendChild(css);
    }

    // ---------- iOS Safari: force inline playback as early as possible ----------
    // Without playsinline, iPhone Safari jumps into native fullscreen on play.
    function forceInline(v) {
        if (!v || v.tagName !== 'VIDEO') return;
        v.setAttribute('playsinline', '');
        v.setAttribute('webkit-playsinline', '');
        v.setAttribute('x5-playsinline', 'true');
        try { v.playsInline = true; } catch (e) {}
    }
    $('video').each(function () { forceInline(this); });

    // Catch videos that Tutor/Plyr inserts later; only inspects added nodes (cheap).
    new MutationObserver(function (muts) {
        for (var i = 0; i < muts.length; i++) {
            var added = muts[i].addedNodes;
            for (var j = 0; j < added.length; j++) {
                var n = added[j];
                if (n.nodeType !== 1) continue;
                if (n.tagName === 'VIDEO') { forceInline(n); bindVideo(n); }
                else if (n.querySelectorAll) {
                    var vs = n.querySelectorAll('video');
                    for (var k = 0; k < vs.length; k++) { forceInline(vs[k]); bindVideo(vs[k]); }
                }
            }
        }
    }).observe(document.documentElement, { childList: true, subtree: true });

    // Backup: loadstart/play fire on media elements without bubbling, so use capture.
    ['loadstart', 'loadedmetadata', 'play'].forEach(function (evt) {
        document.addEventListener(evt, function (e) {
            if (e.target && e.target.tagName === 'VIDEO') { forceInline(e.target); }
        }, true);
    });

    // ---------- Shared state for the current lesson ----------
    var S = null;          // set by initTutorLessonTimer
    var interval = null;

    function stopTimer() {
        if (interval) { clearInterval(interval); interval = null; }
    }

    function fmt(seconds) {
        var m = Math.floor(seconds / 60), s = Math.floor(seconds % 60);
        return m + ':' + (s < 10 ? '0' + s : s);
    }

    function setNavLocked(locked) {
        if (!S) return;
        if (locked && !S.alreadyMet) {
            S.$nav.css({ opacity: '0.3', 'pointer-events': 'none', cursor: 'not-allowed' });
        } else {
            S.$nav.css({ opacity: '', 'pointer-events': '', cursor: '' });
        }
    }

    function setMessage(html) {
        var $a = $('#timer-message-area');
        if ($a.length) { $a.html(html); }
    }

    function countdownHtml() {
        return '⏱ Required minimum study time remaining:<span id="timer-count" class="lt-ok" ' +
            'style="font-weight:700">' + fmt(Math.max(0, REQUIRED_SECONDS - S.activeTime)) + '</span>';
    }

    // What the bar should say right now, based on current progress.
    function defaultMessageHtml() {
        if (!S) { return ''; }
        if (S.alreadyMet) { return '<span class="lt-ok">Lesson requirements already met. Review freely!</span>'; }
        if (timerRequirementMet()) {
            return '<span class="lt-ok">Timer complete! ' +
                (videoRequirementMet() ? 'You may now proceed.' : 'Finish the video to proceed.') + '</span>';
        }
        return countdownHtml();
    }

    // Show a temporary message, then return to the normal status text.
    var msgToken = 0;
    function flashMessage(html, ms) {
        var token = ++msgToken;
        setMessage(html);
        setTimeout(function () {
            if (token === msgToken && S) { setMessage(defaultMessageHtml()); }
        }, ms || 5000);
    }

    function renderTopBar(html) {
        $('#lesson-timer').remove();
        var bar = '<div id="lesson-timer">' +
            '<div><a class="lt-exit" href="' + S.exitUrl + '">\u2190 Exit Course</a></div>' +
            '<div class="lt-msg" id="timer-message-area">' + html + '</div>' +
            '<div class="lt-spacer"></div></div>';
        var $c = $('.tutor-lesson-container').first();
        if (!$c.length) { $c = $('.tutor-single-lesson').first(); }
        if ($c.length) { $c.prepend(bar); } else { $('body').prepend(bar); }
    }

    function videoRequirementMet() {
        var ok = true;
        $('video').each(function () {
            var v = this;
            var st = v._tutorState;
            var dur = v.duration;
            if (!dur || isNaN(dur) || !isFinite(dur)) { return; } // unknown duration: can't judge var max=st ? st.max :0;if (max / dur < VIDEO_THRESHOLD){ok=false}});return ok}function timerRequirementMet(){return S.activeTime>=REQUIRED_SECONDS}function allMet(){return timerRequirementMet() && videoRequirementMet()}function markFinished(){S.alreadyMet=true;store(S.finishedKey,'true');setNavLocked(false)}// ---------- Video binding ---------- function bindVideo(video){if (!S || video._tutorBoundFor===S.id) return;var index=$('video').index(video);if (index < 0) index=0;var timeKey=S.prefix+'video_time_'+index;var maxKey=S.prefix+'video_max_'+index;var st={max:parseFloat(store(maxKey)) || 0,lastSave:0};video._tutorState=st;video._tutorBoundFor=S.id;forceInline(video);var savedTime=parseFloat(store(timeKey)) || 0;function save(force){var now=Date.now();if (force || now - st.lastSave>=SAVE_EVERY_MS){st.lastSave=now;store(timeKey,video.currentTime);store(maxKey,st.max)}}function restore(){if (!S.alreadyMet && savedTime>0 && video.duration && savedTime < video.duration && video.currentTime < savedTime){video.currentTime=savedTime}}if (video.readyState>=1){restore()}else{$(video).off('loadedmetadata.tutorTrack').on('loadedmetadata.tutorTrack',restore)}$(video).off('.tutorTrack2') .on('timeupdate.tutorTrack2',function (){if (video.seeking) return;// Only count natural playback,not a skip that timeupdate saw before 'seeking' fired. if (video.currentTime <=st.max+1.5){st.max=Math.max(video.currentTime, st.max)}save(false)}) .on('seeking.tutorTrack2',function (){if (!S.alreadyMet && video.currentTime>st.max+1){video.currentTime=st.max;flashMessage('<span class="lt-warn">⚠️ You can’t skip ahead in this video. '+'Keep watching, or rewind to review.</span>',5000)}}) .on('pause.tutorTrack2',function (){save(true)}) .on('ended.tutorTrack2',function (){if (video.duration && isFinite(video.duration)){st.max=Math.max(st.max, video.duration)}save(true);if (!S.alreadyMet && !timerRequirementMet()){S.videoWaitingToAdvance=true}}) // iOS native fullscreen events:re-sync when the user comes back. .on('webkitendfullscreen.tutorTrack2 webkitbeginfullscreen.tutorTrack2',function (){save(true)})}// ---------- Main init (runs per lesson) ---------- var runId=0;function initTutorLessonTimer(){stopTimer();$('#lesson-timer').remove();var isLesson=$('body').hasClass('single-lesson') || $('.tutor-single-lesson').length>0;if (!isLesson){S=null;return}var cleanPath=window.location.pathname.replace(/\/+$/,'');var prefix='tutor_'+getUserId()+'_'+cleanPath+'_';var finishedKey=prefix+'fully_met';var timeKey=prefix+'active_seconds';// Only the current lesson's own complete button counts, not sidebar icons.
        var isCompleted = $('.tutor-lesson-done-btn.is-completed').length > 0;

        S = {
            id: ++runId,
            prefix: prefix,
            finishedKey: finishedKey,
            timeKey: timeKey,
            alreadyMet: store(finishedKey) === 'true' || isCompleted,
            activeTime: parseInt(store(timeKey), 10) || 0,
            videoWaitingToAdvance: false,
            exitUrl: window.location.origin + cleanPath.split('/lessons/')[0],
            // Deliberately excludes the whole header so back/menu/sidebar stay usable.
            $nav: $('.tutor-topbar-complete-btn,.tutor-next-link,.tutor-previous-link,' +
                    '.tutor-course-topic-single-footer a,.tutor-lesson-done-btn')
        };

        $('video').each(function () { bindVideo(this); });

        if (S.alreadyMet) {
            setNavLocked(false);
            renderTopBar('<span class="lt-ok">Lesson requirements already met. Review freely!</span>');
            return;
        }

        function showDone() {
            renderTopBar('<span class="lt-ok">Timer complete! You may now proceed.</span>');
        }

        if (timerRequirementMet()) {
            showDone();
            if (allMet()) { markFinished(); } else { setNavLocked(false); }
            return;
        }

        setNavLocked(true);
        renderTopBar('\u23F1 Required minimum study time remaining:<span id="timer-count" class="lt-ok" ' +
            'style="font-weight:700">' + fmt(REQUIRED_SECONDS - S.activeTime) + '</span>');

        var last = Date.now();
        var myRun = S.id;
        interval = setInterval(function () {
            if (!S || S.id !== myRun) { stopTimer(); return; }

            // Tutor re-rendered the container and dropped our bar: put it back, keep counting.
            if (!document.getElementById('lesson-timer')) {
                renderTopBar('\u23F1 Required minimum study time remaining:<span id="timer-count" ' +
                    'class="lt-ok" style="font-weight:700">' + fmt(Math.max(0, REQUIRED_SECONDS - S.activeTime)) + '</span>');
            }

            var now = Date.now();
            if (document.hidden) { last = now; return; }

            var elapsed = (now - last) / 1000;
            last = now;
            // Cap per tick so a locked screen / suspended tab can't be credited as study time. S.activeTime+=Math.min(Math.max(elapsed, 0), MAX_TICK_SECONDS);store(timeKey,Math.floor(S.activeTime));var remaining=REQUIRED_SECONDS - S.activeTime;if (remaining <=0){stopTimer();showDone();if (allMet()){markFinished();if (S.videoWaitingToAdvance){$('.tutor-lesson-done-btn, .tutor-topbar-complete-btn').first().trigger('click')}}else{setNavLocked(false)}}else{$('#timer-count').text(fmt(remaining))}},1000)}// Reset the clock reference when the tab becomes visible again. document.addEventListener('visibilitychange',function (){if (!document.hidden){return}// Flush progress when leaving the page. $('video').each(function (){var v=this,st=v._tutorState;if (!S || !st) return;var i=$('video').index(v);store(S.prefix+'video_time_'+i,v.currentTime);store(S.prefix+'video_max_'+i,st.max)});if (S){store(S.timeKey,Math.floor(S.activeTime))}});// ---------- Completion gate (capture phase so it beats Tutor's own handlers) ----------
    document.addEventListener('click', function (e) {
        if (!S || S.alreadyMet) return;
        var t = e.target;
        if (!t || !t.closest) return;
        if (!t.closest('.tutor-lesson-done-btn,.tutor-topbar-complete-btn')) return;

        if (allMet()) {
            markFinished();
            return; // let Tutor proceed
        }
        e.preventDefault();
        e.stopImmediatePropagation();
        var needTimer = !timerRequirementMet();
        var needVideo = !videoRequirementMet();
        var msg;
        if (needTimer && needVideo) {
            msg = 'Please finish watching the video and wait for the countdown to finish before continuing.';
        } else if (needVideo) {
            msg = 'Please finish watching the video before continuing.';
        } else {
            msg = 'Please wait for the countdown to finish before continuing.';
        }
        flashMessage('<span class="lt-warn">\u26A0\uFE0F ' + msg + '</span>', 5000);
    }, true);

    // ---------- Init + lesson navigation detection ----------
    initTutorLessonTimer();

    // Safari bfcache restore
    window.addEventListener('pageshow', function (event) {
        if (event.persisted) { setTimeout(initTutorLessonTimer, 300); }
    });

    // Tutor swaps lessons without a reload. Cheap URL check instead of observing every DOM mutation.
    var lastUrl = location.href;
    function onUrlMaybeChanged() {
        if (location.href !== lastUrl) {
            lastUrl = location.href;
            setTimeout(initTutorLessonTimer, 600);
        }
    }
    window.addEventListener('popstate',onUrlMaybeChanged);setInterval(onUrlMaybeChanged,1000)});