"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.useIsMyStream = exports.useOffline = exports.intoPlayerProtocol = exports.usePlayerProtocol = exports.makePlayerStore = void 0;
exports.usePlayerContext = usePlayerContext;
exports.getPlayerStoreById = getPlayerStoreById;
exports.getFirstPlayerID = getFirstPlayerID;
exports.getPlayerStoreFromContext = getPlayerStoreFromContext;
exports.usePlayerStore = usePlayerStore;
const tslib_1 = require("tslib");
const react_1 = require("react");
const zustand_1 = require("zustand");
const livestream_store_1 = require("../livestream-store");
const storage_1 = tslib_1.__importDefault(require("../storage"));
const streamplace_store_1 = require("../streamplace-store");
const context_1 = require("./context");
const player_state_1 = require("./player-state");
const PROTOCOL_STORAGE_KEY = "player-protocol";
const makePlayerStore = (id) => {
    const store = (0, zustand_1.createStore)()((set) => ({
        id: id || Math.random().toString(36).slice(8),
        mode: "live",
        setMode: (mode) => set(() => ({ mode })),
        duration: 0,
        setDuration: (duration) => set(() => ({ duration })),
        bufferedEnd: 0,
        setBufferedEnd: (bufferedEnd) => set(() => ({ bufferedEnd })),
        vodLevels: [],
        setVodLevels: (vodLevels) => set(() => ({ vodLevels })),
        playingVODRendition: null,
        setPlayingVODRendition: (playingVODRendition) => set(() => ({ playingVODRendition })),
        selectedRendition: "source",
        setSelectedRendition: (rendition) => set((state) => {
            if (rendition === "audio" && state.controlsTimeout) {
                clearTimeout(state.controlsTimeout);
                return {
                    ...state,
                    selectedRendition: rendition,
                    showControls: true,
                    controlsTimeout: undefined,
                };
            }
            return { ...state, selectedRendition: rendition };
        }),
        protocol: player_state_1.PlayerProtocol.WEBRTC,
        setProtocol: (protocol) => {
            storage_1.default.setItem(PROTOCOL_STORAGE_KEY, protocol).catch(console.error);
            set((state) => ({ ...state, protocol: protocol }));
        },
        src: "",
        setSrc: (src) => set(() => ({ src })),
        ingestMediaSource: undefined,
        setIngestMediaSource: (ingestMediaSource) => set(() => ({ ingestMediaSource })),
        ingestCamera: "user",
        setIngestCamera: (ingestCamera) => set(() => ({ ingestCamera })),
        ingestConnectionState: null,
        setIngestConnectionState: (ingestConnectionState) => set(() => ({ ingestConnectionState })),
        ingestAutoStart: true,
        setIngestAutoStart: (ingestAutoStart) => set(() => ({ ingestAutoStart })),
        ingestStarted: null,
        setIngestStarted: (timestamp) => set(() => ({ ingestStarted: timestamp })),
        stopIngest: () => {
            set(() => ({
                ingestLive: false,
                ingestConnectionState: "new",
                ingestStarted: null,
            })),
                setTimeout(() => set(() => ({
                    ingestLive: false,
                    ingestConnectionState: "new",
                    ingestStarted: null,
                })), 200);
        },
        fullscreen: false,
        setFullscreen: (isFullscreen) => set(() => ({ fullscreen: isFullscreen })),
        status: player_state_1.PlayerStatus.START,
        setStatus: (status) => set(() => ({ status })),
        playTime: 0,
        setPlayTime: (playTime) => set(() => ({ playTime })),
        seekTo: (time) => set((state) => {
            const ref = state.videoRef;
            if (ref && typeof ref === "object" && "current" in ref && ref.current) {
                ref.current.currentTime = time;
            }
            return { playTime: time };
        }),
        videoRef: undefined,
        setVideoRef: (videoRef) => set(() => ({ videoRef })),
        pipMode: false,
        setPipMode: (pipMode) => set(() => ({ pipMode })),
        // Picture-in-Picture action function (set by player component)
        pipAction: undefined,
        setPipAction: (action) => set(() => ({ pipAction: action })),
        togglePlayPause: () => set((state) => {
            const ref = state.videoRef;
            if (ref && typeof ref === "object" && "current" in ref && ref.current) {
                if (ref.current.paused) {
                    ref.current.play();
                }
                else {
                    ref.current.pause();
                }
            }
            return {};
        }),
        setTogglePlayPause: (fn) => set(() => ({ togglePlayPause: fn })),
        // Player element width/height setters for global sync
        playerWidth: undefined,
        setPlayerWidth: (playerWidth) => set(() => ({ playerWidth })),
        playerHeight: undefined,
        setPlayerHeight: (playerHeight) => set(() => ({ playerHeight })),
        // * Whether mute was forced by the browser or not for autoplay
        // * Will get set to 'false' if the user has interacted with the volume
        muteWasForced: false,
        setMuteWasForced: (muteWasForced) => set(() => ({ muteWasForced })),
        autoplayFailed: false,
        setAutoplayFailed: (autoplayFailed) => set(() => ({ autoplayFailed })),
        embedded: false,
        setEmbedded: (embedded) => set(() => ({ embedded })),
        showControls: true,
        controlsTimeout: undefined,
        setShowControls: (showControls) => set({ showControls, controlsTimeout: undefined }),
        telemetry: true,
        setTelemetry: (telemetry) => set(() => ({ telemetry })),
        ingestLive: false,
        setIngestLive: (ingestLive) => set(() => ({ ingestLive })),
        reportingURL: null,
        setReportingURL: (reportingURL) => set(() => ({ reportingURL })),
        playerEvent: async (url, time, eventType, meta) => set((x) => {
            const data = {
                time: time,
                playerId: x.id,
                eventType: eventType,
                meta: {
                    ...meta,
                },
            };
            try {
                // fetch url from sp provider
                const reportingURL = x.reportingURL ?? `${url}/api/player-event`;
                fetch(reportingURL, {
                    method: "POST",
                    body: JSON.stringify(data),
                });
            }
            catch (e) {
                console.error("error sending player telemetry", e);
            }
            return {};
        }),
        // Clear the controls timeout, if it exists.
        // Should be called on player unmount.
        clearControlsTimeout: () => set((state) => {
            if (state.controlsTimeout) {
                clearTimeout(state.controlsTimeout);
            }
            return { controlsTimeout: undefined };
        }),
        setUserInteraction: () => set((p) => {
            if (p.controlsTimeout) {
                clearTimeout(p.controlsTimeout);
            }
            if (p.selectedRendition === "audio") {
                return { showControls: true, controlsTimeout: undefined };
            }
            let controlsTimeout = setTimeout(() => p.setShowControls(false), 1000);
            return { showControls: true, controlsTimeout };
        }),
        showDebugInfo: false,
        setShowDebugInfo: (showDebugInfo) => set(() => ({ showDebugInfo })),
        modMessage: null,
        setModMessage: (modMessage) => set(() => ({ modMessage })),
        reportModalOpen: false,
        setReportModalOpen: (reportModalOpen) => set(() => ({ reportModalOpen })),
        reportSubject: null,
        setReportSubject: (subject) => set(() => ({ reportSubject: subject })),
    }));
    // Load persisted protocol from storage asynchronously
    (async () => {
        try {
            const storedProtocol = await storage_1.default.getItem(PROTOCOL_STORAGE_KEY);
            if (storedProtocol &&
                Object.values(player_state_1.PlayerProtocol).includes(storedProtocol)) {
                store.setState({ protocol: storedProtocol });
            }
        }
        catch (error) {
            console.error("Failed to load player protocol from storage:", error);
        }
    })();
    return store;
};
exports.makePlayerStore = makePlayerStore;
function usePlayerContext() {
    const context = (0, react_1.useContext)(context_1.PlayerContext);
    if (!context) {
        throw new Error("usePlayerContext must be used within a PlayerProvider");
    }
    return context;
}
// Get a specific player store by ID
function getPlayerStoreById(id) {
    const { players } = usePlayerContext();
    const playerStore = players[id];
    if (!playerStore) {
        throw new Error(`No player found with ID: ${id}`);
    }
    return playerStore;
}
// Will get the first player ID in the context
function getFirstPlayerID() {
    const { players } = usePlayerContext();
    const playerIds = Object.keys(players);
    if (playerIds.length === 0) {
        throw new Error("No players found in context");
    }
    return playerIds[0];
}
function getPlayerStoreFromContext() {
    console.warn("getPlayerStoreFromContext is deprecated. Use getPlayerStoreById instead.");
    const { players } = usePlayerContext();
    const playerIds = Object.keys(players);
    if (playerIds.length === 0) {
        throw new Error("No players found in context");
    }
    return players[playerIds[0]];
}
// Use a specific player store by ID
// If no ID is provided, it will use the first player in the context
function usePlayerStore(selector, playerId) {
    if (!playerId) {
        playerId = Object.keys(usePlayerContext().players)[0];
    }
    const store = getPlayerStoreById(playerId);
    return (0, zustand_1.useStore)(store, selector);
}
/* Convenience selectors/hooks */
const usePlayerProtocol = (playerId) => usePlayerStore((x) => [x.protocol, x.setProtocol], playerId);
exports.usePlayerProtocol = usePlayerProtocol;
const intoPlayerProtocol = (protocol) => {
    switch (protocol) {
        case "hls":
            return player_state_1.PlayerProtocol.HLS;
        case "progressive-mp4":
            return player_state_1.PlayerProtocol.PROGRESSIVE_MP4;
        case "progressive-webm":
            return player_state_1.PlayerProtocol.PROGRESSIVE_WEBM;
        default:
            return player_state_1.PlayerProtocol.WEBRTC;
    }
};
exports.intoPlayerProtocol = intoPlayerProtocol;
// returns true if the livestream has been offline for more than 10 seconds and we're not playing
const useOffline = () => {
    const status = usePlayerStore((x) => x.status);
    const segment = (0, livestream_store_1.useLivestreamStore)((x) => x.segment);
    const [now, setNow] = (0, react_1.useState)(Date.now());
    (0, react_1.useEffect)(() => {
        const interval = setInterval(() => {
            setNow(Date.now());
        }, 500);
        return () => clearInterval(interval);
    }, []);
    if (status === player_state_1.PlayerStatus.PLAYING) {
        return false;
    }
    if (!segment?.startTime) {
        return false;
    }
    return now - Date.parse(segment.startTime) > 10000;
};
exports.useOffline = useOffline;
const useIsMyStream = () => {
    const myHandle = (0, streamplace_store_1.useStreamplaceStore)((state) => state.handle);
    const myDid = (0, streamplace_store_1.useStreamplaceStore)((state) => state.oauthSession?.did);
    const channelId = usePlayerStore((state) => state.src);
    return () => {
        return myHandle === channelId || myDid === channelId;
    };
};
exports.useIsMyStream = useIsMyStream;
//# sourceMappingURL=player-store.js.map