<?php
/**
 * Full-screen intro video shown once on arrival, fading into the page.
 *
 * PAGE-SCOPED, like every other piece of page chrome: the keys live in the
 * page's own settings, so an intro set on the home page never appears anywhere
 * else (Sergei 2026-08-03: "It can not affect all pages"). Opt-in by definition,
 * since an empty `intro_video` renders nothing at all.
 *
 * Shared by templates/impulse-page.php (frontend) and
 * admin/views/impulse-preview.php (editor) so the two renderers cannot drift,
 * the same arrangement impulse-brand-logo.php uses.
 *
 * Constraints that shaped this:
 *   - Autoplay is only permitted MUTED, everywhere, so it plays muted. There is
 *     no unmute control: this is a few seconds of atmosphere, not a player.
 *   - The overlay is a SIBLING of the content, never a wrapper, so the page
 *     still paints and a crawler reads it normally.
 *   - preload="none" + poster keeps the video off the critical path: the poster
 *     is what the visitor sees for the first frames, not a blank rectangle.
 *   - NO visible controls: a home-page intro is short and self-terminating, so a
 *     skip button is chrome nobody needs. Escape, reduced-motion, saveData, a
 *     per-page seconds cap and a watchdog all still lead out, because a bad
 *     network must never brick a site.
 *   - It dissolves INTO the page, starting 0.45s before the final frame, rather
 *     than cutting to a still and then fading.
 *
 * @since 2.1.2840
 */

if (!defined('ABSPATH')) exit;

if (!function_exists('impulse_intro_video_html')) {
    /**
     * @param array $s        Page settings.
     * @param int   $pageId   Used for the per-page "seen" key: a visitor who has
     *                        seen THIS page's intro still gets another page's.
     * @param bool  $isEditor Editor renders it dormant (see the JS below).
     */
    function impulse_intro_video_html(array $s, int $pageId, bool $isEditor = false): string
    {
        $url = trim((string) ($s['intro_video'] ?? ''));
        if ($url === '') {
            return '';
        }

        $poster    = trim((string) ($s['intro_poster'] ?? ''));
        $freq      = (($s['intro_frequency'] ?? 'session') === 'always') ? 'always' : 'session';
        // A CAP, not the primary end. The video's own 'ended' wins when it fires
        // first; this covers a client uploading a 90s reel, a stall mid-buffer, or
        // a slow line turning a 5s clip into 20 (Sergei 2026-08-03).
        $maxSecs = max(2, min(60, (int) ($s['intro_max_seconds'] ?? 6)));
        $skipMobile = !empty($s['intro_skip_mobile']);
        $id         = 'impulse-intro-' . $pageId;

        // Dissolves INTO the page: the overlay is a sibling, so the page is already
        // painted underneath and dropping opacity reveals it. The slight scale is
        // what sells "the film opens into the site"; opacity alone reads flat.
        $css =
            '#' . $id . '{position:fixed;inset:0;z-index:99999;background:#000;display:flex;'
          . 'align-items:center;justify-content:center;opacity:1;transform:scale(1);'
          . 'transition:opacity .7s ease-in-out,transform .7s ease-in-out}'
          . '#' . $id . '.is-out{opacity:0;transform:scale(1.04);pointer-events:none}'
          . '#' . $id . ' video{width:100%;height:100%;object-fit:cover;display:block}'
          . '@media(prefers-reduced-motion:reduce){#' . $id . '{transition:none}}';
        if (function_exists('wp_add_inline_style')) {
            wp_add_inline_style('instinctor-page-inline', $css);
        }

        // No controls, deliberately. A home-page intro is a few seconds long and
        // always self-terminates; a skip button on top of that is chrome nobody
        // needs. Escape still works (invisible, costs nothing) and the watchdog
        // below guarantees an exit, because a bad network must never brick a site.
        $html = '<div id="' . esc_attr($id) . '" class="impulse-intro-video" role="presentation" aria-hidden="true">'
              . '<video muted playsinline autoplay preload="none"'
              . ($poster !== '' ? ' poster="' . esc_url($poster) . '"' : '')
              . '><source src="' . esc_url($url) . '"></video>'
              . '</div>';

        // The runtime. Small and defensive: every failure path ends with the
        // overlay gone rather than a visitor stuck behind a black rectangle.
        $js = '(function(){var el=document.getElementById("' . esc_js($id) . '");if(!el)return;'
            . 'var v=el.querySelector("video"),done=false,'
            . 'KEY="impulse_intro_' . esc_js((string) $pageId) . '";'
            . 'function out(){if(done)return;done=true;el.classList.add("is-out");'
            . 'document.documentElement.style.overflow="";'
            . 'setTimeout(function(){if(el.parentNode)el.parentNode.removeChild(el);},800);}'
            // Every reason to never show it, settled before a byte of video loads.
            . 'var reduce=window.matchMedia&&matchMedia("(prefers-reduced-motion:reduce)").matches;'
            . 'var save=navigator.connection&&navigator.connection.saveData;'
            . 'var narrow=' . ($skipMobile ? 'window.innerWidth<768' : 'false') . ';'
            . 'var seen=false;try{seen=' . ($freq === 'session' ? 'sessionStorage.getItem(KEY)==="1"' : 'false') . ';}catch(e){}'
            . ($isEditor ? 'var editor=true;' : 'var editor=false;')
            . 'if(reduce||save||narrow||seen||editor){out();return;}'
            . 'try{' . ($freq === 'session' ? 'sessionStorage.setItem(KEY,"1");' : '') . '}catch(e){}'
            . 'document.documentElement.style.overflow="hidden";'
            . 'v.play().catch(function(){out();});'   // a blocked autoplay must not strand anyone
            // Start dissolving BEFORE the last frame: ending on a hard cut to a
            // still frame is what makes an intro read as cheap. 0.45s of overlap
            // means the page is emerging while the film is still moving.
            . 'v.addEventListener("timeupdate",function(){'
            . 'if(v.duration&&isFinite(v.duration)&&v.duration-v.currentTime<=0.45)out();});'
            . 'v.addEventListener("ended",out);'
            . 'v.addEventListener("error",out);'
            . 'document.addEventListener("keydown",function(k){if(k.key==="Escape")out();});'
            // Hard cap, whatever the file turns out to be.
            . 'setTimeout(out,' . ($maxSecs * 1000) . ');'
            // Last resort if even the cap is somehow missed.
            . 'setTimeout(function(){if(document.body.contains(el))out();},60000);'
            . '})();';
        if (function_exists('wp_add_inline_script')) {
            wp_add_inline_script('instinctor-frontend-js', $js, 'after');
        }

        return $html;
    }
}
