import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
import * as React from 'react';
import { PlayFill } from '@gravity-ui/icons';
import { Icon } from '@gravity-ui/uikit';
import debounce from "lodash/debounce.js";
import _ReactPlayer from 'react-player';
import { MobileContext } from "../../gravity-blocks/context/mobileContext/index.js";
import { VideoContext } from "../../gravity-blocks/context/videoContext/index.js";
import { useAnalytics, useImageSize, useMount } from "../../gravity-blocks/hooks/index.js";
import { CustomControlsButtonPositioning, CustomControlsType, DefaultEventNames, MediaVideoControlsType, PlayButtonThemes, PlayButtonType, PredefinedEventTypes, } from "../../models/index.js";
import { block } from "../../utils/index.js";
import CustomBarControls from "./CustomBarControls.js";
import { i18n } from "./i18n/index.js";
import { checkYoutubeVideos } from "./utils.js";
import { isYoutubePlayerInstance } from "./utils/youtube.js";
import './ReactPlayer.css';
const b = block('ReactPlayer');
const FPS = 60;
const ReactPlayer = 'default' in _ReactPlayer && _ReactPlayer.default
    ? _ReactPlayer.default
    : _ReactPlayer;
// eslint-disable-next-line react/display-name
export const ReactPlayerBlock = React.forwardRef((props, originRef) => {
    const isMobile = React.useContext(MobileContext);
    const { src, previewImgUrl, loop = false, controls = MediaVideoControlsType.Default, customControlsOptions = {}, muted: initiallyMuted = false, elapsedTime, playButton, className, customBarControlsClassName, showPreview, onClickPreview, onIntrinsicSizeChange, disableAutoSizing, analyticsEvents, height, ariaLabel, ratio, autoRatio, contain = true, } = props;
    const { type = PlayButtonType.Default, theme = PlayButtonThemes.Blue, text, className: buttonClassName, } = playButton || {};
    const { type: customControlsType = CustomControlsType.WithMuteButton, muteButtonShown, positioning = CustomControlsButtonPositioning.Center, } = customControlsOptions;
    const autoPlay = Boolean(!isMobile && !previewImgUrl && props.autoplay);
    const mute = initiallyMuted || autoPlay;
    const { playingVideoRef, setProps } = React.useContext(VideoContext);
    const ref = React.useRef(null);
    const buttonRef = React.useRef(null);
    const [playerRef, setPlayerRef] = React.useState();
    const [isPlaying, setIsPlaying] = React.useState(autoPlay);
    const [playedPercent, setPlayedPercent] = React.useState(0);
    const [currentHeight, setCurrentHeight] = React.useState(height);
    const [duration, setDuration] = React.useState(null);
    const [width, setWidth] = React.useState(0);
    const [actualRatio, setActualRatio] = React.useState();
    const [muted, setMuted] = React.useState(mute);
    const [started, setStarted] = React.useState(autoPlay);
    const [ended, setEnded] = React.useState(false);
    const [isMounted, setIsMounted] = React.useState(false);
    const [hovered, setHovered] = React.useState(isMobile);
    useMount(() => setIsMounted(true));
    const videoSrc = React.useMemo(() => checkYoutubeVideos(src), [src]);
    const { imageRef: previewImgRef, onLoad: onPreviewImgLoad } = useImageSize({
        onIntrinsicSizeChange,
    });
    const eventsArray = React.useMemo(() => {
        if (analyticsEvents) {
            return Array.isArray(analyticsEvents) ? analyticsEvents : [analyticsEvents];
        }
        return [];
    }, [analyticsEvents]);
    const handleAnalytics = useAnalytics(DefaultEventNames.ReactPlayerControls);
    React.useImperativeHandle(originRef, () => {
        if (!playerRef) {
            return;
        }
        let play, pause, addEventListener;
        const videoInstance = playerRef.getInternalPlayer();
        if (isYoutubePlayerInstance(videoInstance)) {
            ({ pauseVideo: pause, playVideo: play, addEventListener } = videoInstance);
        }
        else {
            // it is assumed that `videoInstance` is HTMLVideoElement by default
            ({ play, pause, addEventListener } = videoInstance);
        }
        // eslint-disable-next-line consistent-return
        return {
            play: play.bind(videoInstance),
            pause: pause.bind(videoInstance),
            addEventListener: addEventListener.bind(videoInstance),
        };
    }, [playerRef]);
    React.useEffect(() => {
        if (ref.current && !playingVideoRef?.contains(ref.current)) {
            setMuted(true);
        }
    }, [playingVideoRef]);
    React.useEffect(() => {
        if (showPreview) {
            playerRef?.showPreview();
        }
    }, [showPreview, playerRef]);
    React.useEffect(() => {
        if (playerRef && !started) {
            setIsPlaying(autoPlay);
        }
    }, [autoPlay, playerRef, started]);
    React.useEffect(() => setMuted(mute), [mute]);
    React.useEffect(() => {
        if (!started && isPlaying) {
            setStarted(true);
        }
    }, [isPlaying, started]);
    React.useEffect(() => {
        if (started && !Number.isNaN(Number(elapsedTime))) {
            playerRef?.seekTo(elapsedTime ?? 0, 'seconds');
        }
    }, [elapsedTime, playerRef, started]);
    React.useEffect(() => {
        if (disableAutoSizing) {
            return;
        }
        const updateSize = debounce(() => {
            if (ref.current) {
                // We need to get parent's width does not equal 0
                const parentElement = getParentElement(ref.current);
                const { paddingLeft, paddingRight } = getComputedStyle(parentElement);
                const newWidth = parentElement.offsetWidth -
                    parseFloat(paddingLeft) -
                    parseFloat(paddingRight);
                setWidth(newWidth);
                setCurrentHeight(Math.floor(getHeight(newWidth, ratio ?? (autoRatio ? actualRatio : undefined))));
            }
        }, 200);
        updateSize();
        window.addEventListener('resize', updateSize, { passive: true });
        // eslint-disable-next-line consistent-return
        return () => {
            window.removeEventListener('resize', updateSize);
        };
    }, [actualRatio, autoRatio, disableAutoSizing, playerRef, ratio]);
    const playEvents = React.useMemo(() => eventsArray?.filter((e) => e.type === PredefinedEventTypes.Play), [eventsArray]);
    const stopEvents = React.useMemo(() => eventsArray?.filter((e) => e.type === PredefinedEventTypes.Stop), [eventsArray]);
    const playIcon = React.useMemo(() => {
        let playButtonContent;
        switch (type) {
            case PlayButtonType.Text:
                playButtonContent = text;
                break;
            case PlayButtonType.Default:
            default:
                playButtonContent = _jsx(Icon, { className: b('icon'), data: PlayFill, size: 24 });
                break;
        }
        return (_jsx("button", { className: b('button', { theme, text: Boolean(text) }, buttonClassName), "aria-label": i18n('play'), ref: buttonRef, children: playButtonContent }));
    }, [type, theme, text, buttonClassName]);
    const changeMute = React.useCallback((isMuted) => {
        if (isMuted &&
            playerRef &&
            controls === MediaVideoControlsType.Custom &&
            customControlsType === CustomControlsType.WithMuteButton) {
            playerRef.seekTo(0);
            setPlayedPercent(0);
        }
        const events = isMuted ? playEvents : stopEvents;
        handleAnalytics(events);
        if (isMuted) {
            setProps({ playingVideoRef: ref.current });
        }
        // In order to the progress bar to update (equals 0) before displaying
        setTimeout(() => setMuted(!isMuted), 0);
    }, [
        playerRef,
        customControlsType,
        playEvents,
        stopEvents,
        handleAnalytics,
        setProps,
        controls,
    ]);
    const handleClickPreview = React.useCallback(() => {
        setIsPlaying(true);
        onClickPreview?.();
        handleAnalytics(playEvents);
    }, [onClickPreview, handleAnalytics, playEvents]);
    const onPause = React.useCallback(() => {
        // For support correct state for youtube
        if (controls !== MediaVideoControlsType.Custom ||
            customControlsType !== CustomControlsType.WithMuteButton) {
            setIsPlaying(false);
        }
    }, [controls, customControlsType]);
    const onStart = React.useCallback(() => {
        if (!autoPlay && !initiallyMuted) {
            setMuted(false);
        }
    }, [autoPlay, initiallyMuted]);
    const onPlay = React.useCallback(() => {
        setIsPlaying(true);
        if (controls === MediaVideoControlsType.Custom &&
            customControlsType === CustomControlsType.WithMuteButton) {
            if (ended) {
                changeMute(false);
            }
            else if (!isPlaying) {
                changeMute(muted);
            }
            setEnded(false);
        }
    }, [changeMute, controls, customControlsType, ended, isPlaying, muted]);
    const onReady = React.useCallback((player) => {
        setPlayerRef(player);
        const videoElement = player.getInternalPlayer();
        const videoWidth = videoElement.videoWidth;
        const videoHeight = videoElement.videoHeight;
        if (videoWidth && videoHeight) {
            setActualRatio(videoHeight / videoWidth);
            onIntrinsicSizeChange?.({ width: videoWidth, height: videoHeight });
        }
    }, [onIntrinsicSizeChange]);
    const onProgress = React.useCallback(({ played, playedSeconds }) => {
        setPlayedPercent(played);
        if (loop) {
            const { start = 0, end = duration } = typeof loop === 'boolean' ? {} : loop;
            // Youtube videos not muted after finishing playing and start again.
            // 'onEnded' does not fire when 'loop' is set to true.
            // It is custom loop with muted sound after finishing playing and start again.
            if (end !== null && playedSeconds >= end) {
                setIsPlaying(true);
                playerRef?.seekTo(start);
            }
        }
        if (played === 1) {
            setMuted(true);
        }
    }, [duration, loop, playerRef]);
    const onDuration = React.useCallback((currentDuration) => {
        setDuration(currentDuration);
    }, []);
    const onEnded = React.useCallback(() => {
        setEnded(true);
    }, []);
    const onPlayClick = React.useCallback(() => {
        if (isPlaying) {
            onPause();
        }
        else {
            onPlay();
        }
    }, [isPlaying, onPlay, onPause]);
    const handleClick = React.useCallback(() => {
        buttonRef.current?.click();
        if (controls === MediaVideoControlsType.Custom) {
            if (customControlsType === CustomControlsType.WithMuteButton) {
                changeMute(muted);
            }
            else {
                onPlayClick();
            }
        }
    }, [controls, customControlsType, changeMute, muted, onPlayClick]);
    const handleKeyDown = React.useCallback((e) => {
        const key = e.key.toLowerCase();
        if (key === 'enter') {
            buttonRef.current?.click();
        }
    }, []);
    const onFocusIn = React.useCallback(() => setHovered(true), []);
    const onFocusOut = React.useCallback(() => setHovered(false), []);
    return (_jsx("div", { className: b({
            wrapper: !currentHeight,
            controls,
            contain,
            'auto-ratio': autoRatio,
        }, className), ref: ref, onClick: handleClick, onMouseEnter: onFocusIn, onMouseLeave: onFocusOut, onFocus: onFocusIn, onBlur: onFocusOut, onKeyDown: handleKeyDown, role: "button", tabIndex: 0, children: isMounted ? (_jsxs(React.Fragment, { children: [_jsx(ReactPlayer, { className: b('player'), url: videoSrc, muted: muted, controls: controls === MediaVideoControlsType.Default, height: currentHeight || '100%', width: width || '100%', light: previewImgUrl && (_jsx("img", { className: b('preview-img'), src: previewImgUrl, onLoad: onPreviewImgLoad, alt: "", "aria-hidden": true, ref: previewImgRef })), playing: isPlaying, playIcon: playIcon, progressInterval: FPS, onClickPreview: handleClickPreview, onStart: onStart, onReady: onReady, onPlay: onPlay, onPause: autoPlay && customControlsType !== CustomControlsType.WithMuteButton
                        ? undefined
                        : onPause, onProgress: onProgress, onEnded: onEnded, onDuration: onDuration, "aria-label": ariaLabel, previewTabIndex: -1, config: {
                        file: {
                            attributes: {
                                pip: isMobile ? 'false' : undefined,
                                playsinline: isMobile ? '' : undefined,
                                disablepictureinpicture: isMobile ? '' : undefined,
                            },
                        },
                    } }), controls === MediaVideoControlsType.Custom && (_jsx(CustomBarControls, { className: customBarControlsClassName, mute: {
                        isMuted: muted,
                        changeMute: (event) => {
                            event.stopPropagation();
                            changeMute(muted);
                        },
                    }, elapsedTimePercent: playedPercent, type: customControlsType, isPaused: !isPlaying, onPlayClick: onPlayClick, muteButtonShown: muteButtonShown, shown: hovered && ((!started && !previewImgUrl) || started), positioning: positioning }))] })) : null }));
});
function getHeight(width, ratio = 9 / 16) {
    return width * ratio;
}
function getParentElement(element) {
    const parentElement = element.parentElement;
    if (!parentElement) {
        return element;
    }
    return parentElement.offsetWidth ? parentElement : getParentElement(parentElement);
}
export default ReactPlayerBlock;
//# sourceMappingURL=ReactPlayer.js.map
