import React, { memo, useCallback, useMemo, useState, useEffect, forwardRef, useRef, useImperativeHandle, } from 'react';
import { st, classes, vars } from './AudioPlayer.st.css.js';
import Tooltip from '../Tooltip';
import IconButton from '../IconButton';
import Loader from '../Loader';
import Heading from '../Heading';
import { PlayFilled, PauseFilled } from '@wix/wix-ui-icons-common';
import { dataHooks } from './constants';
import { useAudioManager } from './AudioManager/AudioManager';
import { positionToSeconds, secondsToISO, secondsToPosition } from './utils';
import { useIcons } from '../WixDesignSystemIconThemeProvider';
/** AudioPlayer */
const AudioPlayer = memo(forwardRef(({ dataHook, className, src, format, preload = 'metadata', webAudioAPI = false, onLoad, onLoadError, onPlay, onPause, onEnd, onSeek, autoplay, volume, }, ref) => {
    const icons = useIcons('AudioPlayer', {
        PlayFilled,
        PauseFilled,
    });
    const [isSliderLocked, setIsSliderLocked] = useState(true);
    const [hoverPosition, setHoverPosition] = useState(0);
    const [handleSizeInPercentage, setHandleSizeInPercentage] = useState(0);
    const [playing, setPlaying] = useState(false);
    const [showDuration, setShowDuration] = useState(true);
    const playPauseButtonRef = useRef(null);
    useImperativeHandle(ref, () => ({
        focus: () => playPauseButtonRef.current && playPauseButtonRef.current.focus(),
    }));
    const _onDestroy = useCallback(() => {
        setPlaying(false);
        setShowDuration(true);
    }, [setPlaying, setShowDuration]);
    const _onEnd = useCallback(() => {
        setShowDuration(true);
        setPlaying(false);
        onEnd && onEnd();
    }, [onEnd, setShowDuration, setPlaying]);
    const _onLoad = useCallback(() => {
        if (autoplay) {
            setShowDuration(false);
            setPlaying(true);
        }
        onLoad && onLoad();
    }, [onLoad, autoplay]);
    const { loadingState, duration, seek, setSeek } = useAudioManager({
        src,
        format,
        preload,
        webAudioAPI,
        volume,
        onLoad: _onLoad,
        onLoadError,
        onPlay,
        onSeek,
        onPause,
        playing,
        onDestroy: _onDestroy,
        onEnd: _onEnd,
        allowSeekLoop: isSliderLocked,
    });
    const isLoaded = loadingState === 'loaded';
    const _hoverISO = useMemo(() => {
        if (!isLoaded) {
            return secondsToISO(0, false, duration);
        }
        return secondsToISO(positionToSeconds(hoverPosition, duration), true, duration);
    }, [isLoaded, hoverPosition, duration]);
    // takes the current seek (in seconds) and converts it to slider position.
    const _seekPercentage = useMemo(() => {
        if (!isLoaded) {
            return 0;
        }
        return secondsToPosition(seek, duration);
    }, [isLoaded, seek, duration]);
    const _togglePlayPause = useCallback(() => {
        setShowDuration(false);
        if (playing) {
            setPlaying(false);
        }
        else {
            setPlaying(true);
        }
    }, [playing, setPlaying, setShowDuration]);
    const _playPauseButtonContent = useMemo(() => {
        if (loadingState === 'loading') {
            return (React.createElement("span", { "data-hook": dataHooks.audioPlayerLoad },
                React.createElement(Loader, { size: "tiny" })));
        }
        return playing ? (React.createElement(icons.PauseFilled, { "data-hook": dataHooks.audioPlayerPause })) : (React.createElement(icons.PlayFilled, { "data-hook": dataHooks.audioPlayerPlay }));
    }, [loadingState, playing, icons]);
    const _setSliderPositions = useCallback((x, width, clickX) => {
        const positionInPixels = ((clickX - x) / width) * 100;
        const position = Math.min(Math.max(positionInPixels, 0), 100);
        setHandleSizeInPercentage((12 / width) * 100);
        setHoverPosition(position);
    }, [setHoverPosition]);
    const _handleSliderMouseDown = useCallback(event => {
        const { clientX, currentTarget } = event;
        const { x, width } = currentTarget.getBoundingClientRect();
        setIsSliderLocked(false);
        _setSliderPositions(x, width, clientX);
    }, [_setSliderPositions, setIsSliderLocked]);
    const _handleSliderMouseMove = useCallback(event => {
        const { clientX, currentTarget } = event;
        const { x, width } = currentTarget.getBoundingClientRect();
        _setSliderPositions(x, width, clientX);
    }, [_setSliderPositions]);
    const _handleSliderMouseUp = useCallback(() => {
        setIsSliderLocked(true);
    }, [setIsSliderLocked]);
    useEffect(() => {
        window.addEventListener('mouseup', _handleSliderMouseUp);
        return () => window.removeEventListener('mouseup', _handleSliderMouseUp);
    }, [_handleSliderMouseUp]);
    // seek audio file to the slider location when dragged.
    useEffect(() => {
        if (!isSliderLocked) {
            setSeek(positionToSeconds(hoverPosition, duration));
            setShowDuration(false);
        }
    }, [duration, hoverPosition, isSliderLocked, setSeek]);
    return (React.createElement("div", { className: st(classes.root, className), "data-hook": dataHook },
        React.createElement(IconButton, { ref: playPauseButtonRef, size: "small", onClick: _togglePlayPause, dataHook: dataHooks.audioPlayerPlayPause, className: classes.playPauseButton }, _playPauseButtonContent),
        React.createElement("div", { "data-hook": dataHooks.audioPlayerSlider, className: classes.slider, style: {
                [vars['audio-player-position']]: `${_seekPercentage}%`,
            }, onMouseDown: _handleSliderMouseDown, onMouseMove: _handleSliderMouseMove },
            React.createElement("div", { className: classes.track }),
            React.createElement("div", { className: classes.tooltip, style: { left: `${hoverPosition}%` } },
                React.createElement(Tooltip, { content: `${_hoverISO}` },
                    React.createElement("div", { className: classes.tooltipTarget }))),
            React.createElement("div", { "data-hook": dataHooks.audioPlayerSliderHandle, className: st(classes.handle, {
                    grow: isLoaded &&
                        (!isSliderLocked ||
                            Math.abs(_seekPercentage - hoverPosition) <
                                handleSizeInPercentage),
                }), style: { left: `${_seekPercentage}%` } })),
        React.createElement(Heading, { size: "tiny", className: classes.timer, dataHook: dataHooks.audioTimeIndicator }, showDuration
            ? secondsToISO(duration, isLoaded, duration)
            : secondsToISO(seek, isLoaded, duration))));
}));
AudioPlayer.displayName = 'AudioPlayer';
export default AudioPlayer;
//# sourceMappingURL=AudioPlayer.js.map