import React, { useEffect, useState, useRef } from 'react';
import cx from 'classnames';
import {
    formatPlayerTime,
    getProgressPosition,
} from 'src/pages/productModal/components/productTracksAudioPlayer/utils';

interface Props {
    audio: HTMLAudioElement | null;
    disabled?: boolean;
    isPlaying: boolean;
    isActive: boolean;
    duration: number | null;
}

const CLASSNAME = 'AudioPlayerScrubber';
const CLASSNAME_BAR = `${CLASSNAME}-bar`;

const AudioScrubber = ({
    audio,
    duration,
    isActive,
    isPlaying,
    disabled = true,
}: Props) => {
    const [progressPercentage, setProgressPercentage] = useState(0);
    const [isDragging, setIsDragging] = useState(false);
    const progressRef = useRef<HTMLDivElement>(null);
    const isInactive = !disabled && !isActive;

    // Update progress bar while audio is playing
    useEffect(() => {
        if (!audio) return;

        const onUpdateTime = () => {
            if (!isDragging) updateProgressPercentage(audio.currentTime);
        };

        audio.addEventListener('timeupdate', onUpdateTime);

        return () => audio.removeEventListener('timeupdate', onUpdateTime);
        // eslint-disable-next-line react-hooks/exhaustive-deps
    }, [audio, duration, isDragging]);

    const updateProgressPercentage = (newPosition: number) => {
        setProgressPercentage(
            duration && duration > 0 ? (newPosition / duration) * 100 : 0
        );
    };

    const updatePlayerTime = (event: MouseEvent) => {
        if (!audio || !progressRef.current) return;

        const updatedPosition = getProgressPosition(
            event.clientX,
            duration,
            progressRef.current.getBoundingClientRect()
        );

        updateProgressPercentage(updatedPosition);
    };

    const handleDragStart = (event: React.MouseEvent<HTMLDivElement>) => {
        updatePlayerTime(event.nativeEvent);
        setIsDragging(true);

        if (isPlaying) audio?.pause();

        document.addEventListener('mousemove', updatePlayerTime);
        document.addEventListener('mouseup', handleDragEnd);
    };

    const handleDragEnd = (event: MouseEvent) => {
        if (!audio || !progressRef.current) return;

        const updatedPosition = getProgressPosition(
            event.clientX,
            duration,
            progressRef.current.getBoundingClientRect()
        );
        // Modify <audio> currentTime only when released
        audio.currentTime = updatedPosition;

        setIsDragging(false);

        if (isPlaying) void audio?.play();

        document.removeEventListener('mousemove', updatePlayerTime);
        document.removeEventListener('mouseup', handleDragEnd);
    };

    return (
        <div className={CLASSNAME} data-testid={CLASSNAME}>
            <div className={`${CLASSNAME}-time`}>
                {formatPlayerTime(disabled ? null : audio?.currentTime)}
            </div>
            <div
                ref={progressRef}
                className={cx(
                    CLASSNAME_BAR,
                    disabled && `${CLASSNAME_BAR}-disabled`
                )}
                onMouseDown={event => !disabled && handleDragStart(event)}
            >
                {!disabled && (
                    <>
                        <div
                            className={cx(
                                `${CLASSNAME_BAR}-progress`,
                                isInactive &&
                                    `${CLASSNAME_BAR}-progress-inactive`
                            )}
                            style={{ width: `${progressPercentage}%` }}
                        />

                        <div
                            className={cx(
                                `${CLASSNAME_BAR}-thumb`,
                                isInactive && `${CLASSNAME_BAR}-thumb-inactive`
                            )}
                            onMouseDown={event =>
                                !disabled && handleDragStart(event)
                            }
                            style={{ left: `${progressPercentage}%` }}
                        />
                    </>
                )}
            </div>
            <div className={`${CLASSNAME}-time`}>
                {formatPlayerTime(duration)}
            </div>
        </div>
    );
};

export default AudioScrubber;
