/**
 * Unified wrapper around YouTube IFrame Player API and Vimeo Player.js so the
 * rest of the app can drive embedded videos with the same play/pause/seek/
 * volume calls used for `<video>` elements. The provider libraries are lazy-
 * loaded on first use so a project with no embeds doesn't pay the network cost.
 *
 * What this enables:
 *   • Auto-pause embeds when the user navigates away from a slide.
 *   • Reset embed `currentTime` to startTime on slide enter (otherwise YouTube
 *     persists position across iframe rebuilds).
 *   • Render OUR own play/pause/scrub controls on top of the iframe (we hide
 *     YouTube's chrome via `controls=0` in the embed URL).
 *
 * What this does NOT enable: server-side export capture. YouTube/Vimeo render
 * frames inside their player; Puppeteer can't screenshot cross-origin iframe
 * content, so exports of slides containing embeds still fall back to the
 * provider-supplied thumbnail (handled in /present's render path).
 */
let ytApiPromise = null;
export function loadYouTubeAPI() {
    if (typeof window === 'undefined')
        return Promise.reject(new Error('SSR'));
    if (window.YT && window.YT.Player)
        return Promise.resolve(window.YT);
    if (ytApiPromise)
        return ytApiPromise;
    ytApiPromise = new Promise((resolve, reject) => {
        // The IFrame API expects a global callback. Chain any pre-existing one
        // so we play nicely with other libraries on the page.
        const prev = window.onYouTubeIframeAPIReady;
        window.onYouTubeIframeAPIReady = () => {
            if (typeof prev === 'function') {
                try {
                    prev();
                }
                catch { }
            }
            resolve(window.YT);
        };
        const tag = document.createElement('script');
        tag.src = 'https://www.youtube.com/iframe_api';
        tag.async = true;
        tag.onerror = () => reject(new Error('Failed to load YouTube IFrame API'));
        document.head.appendChild(tag);
    });
    return ytApiPromise;
}
let vimeoApiPromise = null;
export function loadVimeoAPI() {
    if (typeof window === 'undefined')
        return Promise.reject(new Error('SSR'));
    const w = window;
    if (w.Vimeo && w.Vimeo.Player)
        return Promise.resolve(w.Vimeo);
    if (vimeoApiPromise)
        return vimeoApiPromise;
    vimeoApiPromise = new Promise((resolve, reject) => {
        const tag = document.createElement('script');
        tag.src = 'https://player.vimeo.com/api/player.js';
        tag.async = true;
        tag.onload = () => resolve(window.Vimeo);
        tag.onerror = () => reject(new Error('Failed to load Vimeo Player API'));
        document.head.appendChild(tag);
    });
    return vimeoApiPromise;
}
export async function createEmbedPlayer(opts) {
    if (opts.provider === 'youtube')
        return createYouTubePlayer(opts);
    return createVimeoPlayer(opts);
}
async function createYouTubePlayer(opts) {
    const YT = await loadYouTubeAPI();
    let stateCbs = [];
    const player = await new Promise((resolve) => {
        const p = new YT.Player(opts.iframe, {
            events: {
                onReady: () => resolve(p),
                onStateChange: (e) => {
                    const map = {
                        [-1]: 'unstarted',
                        [0]: 'ended',
                        [1]: 'playing',
                        [2]: 'paused',
                        [3]: 'buffering',
                        [5]: 'cued'
                    };
                    const state = map[e.data] ?? 'unstarted';
                    for (const cb of stateCbs)
                        try {
                            cb(state);
                        }
                        catch { }
                }
            }
        });
    });
    if (opts.muted)
        player.mute();
    if (opts.startTime)
        try {
            player.seekTo(opts.startTime, true);
        }
        catch { }
    return {
        play: () => player.playVideo(),
        pause: () => player.pauseVideo(),
        seekTo: (s) => player.seekTo(s, true),
        getCurrentTime: async () => Number(player.getCurrentTime()) || 0,
        getDuration: async () => Number(player.getDuration()) || 0,
        setVolume: (v) => player.setVolume(Math.max(0, Math.min(100, v * 100))),
        setMuted: (m) => (m ? player.mute() : player.unMute()),
        setPlaybackRate: (r) => player.setPlaybackRate(r),
        destroy: () => { try {
            player.destroy();
        }
        catch { } },
        onStateChange: (cb) => { stateCbs.push(cb); return () => { stateCbs = stateCbs.filter((f) => f !== cb); }; }
    };
}
async function createVimeoPlayer(opts) {
    const Vimeo = await loadVimeoAPI();
    const player = new Vimeo.Player(opts.iframe);
    let stateCbs = [];
    await player.ready();
    if (opts.muted)
        await player.setMuted(true);
    if (opts.startTime)
        try {
            await player.setCurrentTime(opts.startTime);
        }
        catch { }
    player.on('play', () => stateCbs.forEach((cb) => cb('playing')));
    player.on('pause', () => stateCbs.forEach((cb) => cb('paused')));
    player.on('ended', () => stateCbs.forEach((cb) => cb('ended')));
    player.on('bufferstart', () => stateCbs.forEach((cb) => cb('buffering')));
    return {
        play: () => player.play(),
        pause: () => player.pause(),
        seekTo: (s) => player.setCurrentTime(s),
        getCurrentTime: () => player.getCurrentTime(),
        getDuration: () => player.getDuration(),
        setVolume: (v) => player.setVolume(Math.max(0, Math.min(1, v))),
        setMuted: (m) => player.setMuted(m),
        setPlaybackRate: (r) => player.setPlaybackRate(r),
        destroy: () => { try {
            player.destroy();
        }
        catch { } },
        onStateChange: (cb) => { stateCbs.push(cb); return () => { stateCbs = stateCbs.filter((f) => f !== cb); }; }
    };
}
