import { useEffect, useCallback, useRef, useState } from 'react';

import { defineMessages, useIntl, FormattedMessage } from 'react-intl';

import classNames from 'classnames';

import { useSpring, animated, config } from '@react-spring/web';
import { throttle } from 'lodash';

import Forward5Icon from '@/material-icons/400-24px/forward_5-fill.svg?react';
import FullscreenIcon from '@/material-icons/400-24px/fullscreen.svg?react';
import FullscreenExitIcon from '@/material-icons/400-24px/fullscreen_exit.svg?react';
import PauseIcon from '@/material-icons/400-24px/pause-fill.svg?react';
import PlayArrowIcon from '@/material-icons/400-24px/play_arrow-fill.svg?react';
import RectangleIcon from '@/material-icons/400-24px/rectangle.svg?react';
import Replay5Icon from '@/material-icons/400-24px/replay_5-fill.svg?react';
import VolumeDownIcon from '@/material-icons/400-24px/volume_down-fill.svg?react';
import VolumeOffIcon from '@/material-icons/400-24px/volume_off-fill.svg?react';
import VolumeUpIcon from '@/material-icons/400-24px/volume_up-fill.svg?react';
import { Blurhash } from 'mastodon/components/blurhash';
import { Icon } from 'mastodon/components/icon';
import { SpoilerButton } from 'mastodon/components/spoiler_button';
import {
  isFullscreen,
  requestFullscreen,
  exitFullscreen,
  attachFullscreenListener,
  detachFullscreenListener,
} from 'mastodon/features/ui/util/fullscreen';
import { displayMedia, useBlurhash } from 'mastodon/initial_state';
import { playerSettings } from 'mastodon/settings';

import { HotkeyIndicator } from './components/hotkey_indicator';
import type { HotkeyEvent } from './components/hotkey_indicator';

const messages = defineMessages({
  play: { id: 'video.play', defaultMessage: 'Play' },
  pause: { id: 'video.pause', defaultMessage: 'Pause' },
  mute: { id: 'video.mute', defaultMessage: 'Mute' },
  unmute: { id: 'video.unmute', defaultMessage: 'Unmute' },
  hide: { id: 'video.hide', defaultMessage: 'Hide video' },
  expand: { id: 'video.expand', defaultMessage: 'Expand video' },
  close: { id: 'video.close', defaultMessage: 'Close video' },
  fullscreen: { id: 'video.fullscreen', defaultMessage: 'Full screen' },
  exit_fullscreen: {
    id: 'video.exit_fullscreen',
    defaultMessage: 'Exit full screen',
  },
  volumeUp: { id: 'video.volume_up', defaultMessage: 'Volume up' },
  volumeDown: { id: 'video.volume_down', defaultMessage: 'Volume down' },
  skipForward: { id: 'video.skip_forward', defaultMessage: 'Skip forward' },
  skipBackward: { id: 'video.skip_backward', defaultMessage: 'Skip backward' },
});

const DOUBLE_CLICK_THRESHOLD = 250;
const HOVER_FADE_DELAY = 4000;

export const formatTime = (secondsNum: number) => {
  const hours = Math.floor(secondsNum / 3600);
  const minutes = Math.floor((secondsNum - hours * 3600) / 60);
  const seconds = secondsNum - hours * 3600 - minutes * 60;

  const formattedHours = `${hours < 10 ? '0' : ''}${hours}`;
  const formattedMinutes = `${minutes < 10 ? '0' : ''}${minutes}`;
  const formattedSeconds = `${seconds < 10 ? '0' : ''}${seconds}`;

  return (
    (formattedHours === '00' ? '' : `${formattedHours}:`) +
    `${formattedMinutes}:${formattedSeconds}`
  );
};

export const findElementPosition = (el: HTMLElement) => {
  const box = el.getBoundingClientRect();
  const docEl = document.documentElement;
  const body = document.body;

  const clientLeft = docEl.clientLeft || body.clientLeft || 0;
  const scrollLeft = window.scrollX || body.scrollLeft;
  const left = box.left + scrollLeft - clientLeft;

  const clientTop = docEl.clientTop || body.clientTop || 0;
  const scrollTop = window.scrollY || body.scrollTop;
  const top = box.top + scrollTop - clientTop;

  return {
    left: Math.round(left),
    top: Math.round(top),
  };
};

export const getPointerPosition = (
  el: HTMLElement | null,
  event: MouseEvent,
) => {
  if (!el) {
    return {
      y: 0,
      x: 0,
    };
  }

  const box = findElementPosition(el);
  const boxW = el.offsetWidth;
  const boxH = el.offsetHeight;
  const boxY = box.top;
  const boxX = box.left;

  const { pageY, pageX } = event;

  return {
    y: Math.max(0, Math.min(1, (pageY - boxY) / boxH)),
    x: Math.max(0, Math.min(1, (pageX - boxX) / boxW)),
  };
};

export const fileNameFromURL = (str: string) => {
  const url = new URL(str);
  const pathname = url.pathname;
  const index = pathname.lastIndexOf('/');

  return pathname.slice(index + 1);
};

const frameRateAsNumber = (frameRate: string): number => {
  if (frameRate.includes('/')) {
    return frameRate
      .split('/')
      .map((c) => parseInt(c))
      .reduce((p, c) => p / c);
  }

  return parseInt(frameRate);
};

const persistVolume = (volume: number, muted: boolean) => {
  playerSettings.set('volume', volume);
  playerSettings.set('muted', muted);
};

const restoreVolume = (video: HTMLVideoElement) => {
  const volume = (playerSettings.get('volume') as number | undefined) ?? 0.5;
  const muted = (playerSettings.get('muted') as boolean | undefined) ?? false;

  video.volume = volume;
  video.muted = muted;
};

let hotkeyEventId = 0;

const registerHotkeyEvent = (
  setHotkeyEvents: React.Dispatch<React.SetStateAction<HotkeyEvent[]>>,
  event: Omit<HotkeyEvent, 'key'>,
) => {
  setHotkeyEvents(() => [{ key: hotkeyEventId++, ...event }]);
};

export const Video: React.FC<{
  preview?: string;
  frameRate?: string;
  aspectRatio?: string;
  src: string;
  alt?: string;
  lang?: string;
  sensitive?: boolean;
  onOpenVideo?: (options: {
    startTime: number;
    autoPlay: boolean;
    defaultVolume: number;
  }) => void;
  onCloseVideo?: () => void;
  detailed?: boolean;
  editable?: boolean;
  alwaysVisible?: boolean;
  visible?: boolean;
  onToggleVisibility?: () => void;
  deployPictureInPicture?: (
    type: string,
    mediaProps: {
      src: string;
      muted: boolean;
      volume: number;
      currentTime: number;
    },
  ) => void;
  blurhash?: string;
  startPlaying?: boolean;
  startTime?: number;
  startVolume?: number;
  startMuted?: boolean;
  matchedFilters?: string[];
}> = ({
  preview,
  frameRate = '25',
  aspectRatio,
  src,
  alt = '',
  lang,
  sensitive,
  onOpenVideo,
  onCloseVideo,
  detailed,
  editable,
  alwaysVisible,
  visible,
  onToggleVisibility,
  deployPictureInPicture,
  blurhash,
  startPlaying,
  startTime,
  startVolume,
  startMuted,
  matchedFilters,
}) => {
  const intl = useIntl();
  const [currentTime, setCurrentTime] = useState(0);
  const [duration, setDuration] = useState(0);
  const [volume, setVolume] = useState(0.5);
  const [paused, setPaused] = useState(true);
  const [dragging, setDragging] = useState(false);
  const [fullscreen, setFullscreen] = useState(false);
  const [hovered, setHovered] = useState(false);
  const [muted, setMuted] = useState(false);
  const [revealed, setRevealed] = useState(false);
  const [hotkeyEvents, setHotkeyEvents] = useState<HotkeyEvent[]>([]);

  const playerRef = useRef<HTMLDivElement>(null);
  const videoRef = useRef<HTMLVideoElement | null>(null);
  const seekRef = useRef<HTMLDivElement>(null);
  const volumeRef = useRef<HTMLDivElement>(null);
  const doubleClickTimeoutRef = useRef<ReturnType<typeof setTimeout> | null>();
  const hoverTimeoutRef = useRef<ReturnType<typeof setTimeout> | null>();

  const [style, api] = useSpring(() => ({
    progress: '0%',
    buffer: '0%',
    volume: '0%',
  }));

  const handleVideoRef = useCallback(
    (c: HTMLVideoElement | null) => {
      if (videoRef.current && !videoRef.current.paused && c === null) {
        deployPictureInPicture?.('video', {
          src: src,
          currentTime: videoRef.current.currentTime,
          muted: videoRef.current.muted,
          volume: videoRef.current.volume,
        });
      }

      videoRef.current = c;

      if (videoRef.current) {
        restoreVolume(videoRef.current);
        setVolume(videoRef.current.volume);
        setMuted(videoRef.current.muted);
        void api.start({
          volume: `${videoRef.current.volume * 100}%`,
        });
      }
    },
    [api, setVolume, setMuted, src, deployPictureInPicture],
  );

  const togglePlay = useCallback(() => {
    if (!videoRef.current) {
      return;
    }

    if (videoRef.current.paused) {
      void videoRef.current.play();
    } else {
      videoRef.current.pause();
    }
  }, []);

  const toggleFullscreen = useCallback(() => {
    if (isFullscreen()) {
      exitFullscreen();
    } else {
      requestFullscreen(playerRef.current);
    }
  }, []);

  const toggleMute = useCallback(() => {
    if (!videoRef.current) {
      return;
    }

    const effectivelyMuted =
      videoRef.current.muted || videoRef.current.volume === 0;

    if (effectivelyMuted) {
      videoRef.current.muted = false;

      if (videoRef.current.volume === 0) {
        videoRef.current.volume = 0.05;
      }
    } else {
      videoRef.current.muted = true;
    }
  }, []);

  const handleClickRoot = useCallback((e: React.MouseEvent) => {
    // Stop clicks within the video player e.g. closing parent modal
    e.stopPropagation();
  }, []);

  const handleClick = useCallback(() => {
    if (!doubleClickTimeoutRef.current) {
      doubleClickTimeoutRef.current = setTimeout(() => {
        registerHotkeyEvent(setHotkeyEvents, {
          icon: videoRef.current?.paused ? PlayArrowIcon : PauseIcon,
          label: videoRef.current?.paused ? messages.play : messages.pause,
        });
        togglePlay();
        doubleClickTimeoutRef.current = null;
      }, DOUBLE_CLICK_THRESHOLD);
    } else {
      clearTimeout(doubleClickTimeoutRef.current);
      doubleClickTimeoutRef.current = null;
      registerHotkeyEvent(setHotkeyEvents, {
        icon: isFullscreen() ? FullscreenExitIcon : FullscreenIcon,
        label: isFullscreen() ? messages.exit_fullscreen : messages.fullscreen,
      });
      toggleFullscreen();
    }
  }, [setHotkeyEvents, togglePlay, toggleFullscreen]);

  const handlePlay = useCallback(() => {
    setPaused(false);
  }, [setPaused]);

  const handlePause = useCallback(() => {
    setPaused(true);
  }, [setPaused]);

  useEffect(() => {
    let nextFrame: ReturnType<typeof requestAnimationFrame>;

    const updateProgress = () => {
      nextFrame = requestAnimationFrame(() => {
        if (videoRef.current) {
          const progress =
            videoRef.current.currentTime / videoRef.current.duration;
          void api.start({
            progress: isNaN(progress) ? '0%' : `${progress * 100}%`,
            config: config.stiff,
          });
        }

        updateProgress();
      });
    };

    updateProgress();

    return () => {
      cancelAnimationFrame(nextFrame);
    };
  }, [api]);

  useEffect(() => {
    if (!videoRef.current) {
      return;
    }

    videoRef.current.volume = volume;
    videoRef.current.muted = muted;
  }, [volume, muted]);

  useEffect(() => {
    if (typeof visible !== 'undefined') {
      setRevealed(visible);
    } else {
      setRevealed(
        displayMedia === 'show_all' ||
          (displayMedia !== 'hide_all' && !sensitive),
      );
    }
  }, [visible, sensitive]);

  useEffect(() => {
    if (!revealed && videoRef.current) {
      videoRef.current.pause();
    }
  }, [revealed]);

  useEffect(() => {
    const handleFullscreenChange = () => {
      setFullscreen(isFullscreen());
    };

    const handleScroll = throttle(
      () => {
        if (!videoRef.current) {
          return;
        }

        const { top, height } = videoRef.current.getBoundingClientRect();
        const inView =
          top <=
            (window.innerHeight || document.documentElement.clientHeight) &&
          top + height >= 0;

        if (!videoRef.current.paused && !inView) {
          videoRef.current.pause();

          deployPictureInPicture?.('video', {
            src: src,
            currentTime: videoRef.current.currentTime,
            muted: videoRef.current.muted,
            volume: videoRef.current.volume,
          });
        }
      },
      150,
      { trailing: true },
    );

    attachFullscreenListener(handleFullscreenChange);
    window.addEventListener('scroll', handleScroll);

    return () => {
      window.removeEventListener('scroll', handleScroll);
      detachFullscreenListener(handleFullscreenChange);
    };
  }, [setPaused, setFullscreen, src, deployPictureInPicture]);

  const handleTimeUpdate = useCallback(() => {
    if (!videoRef.current) {
      return;
    }

    setCurrentTime(videoRef.current.currentTime);
  }, [setCurrentTime]);

  const handleVolumeMouseDown = useCallback(
    (e: React.MouseEvent) => {
      const handleVolumeMouseUp = () => {
        document.removeEventListener('mousemove', handleVolumeMouseMove, true);
        document.removeEventListener('mouseup', handleVolumeMouseUp, true);
      };

      const handleVolumeMouseMove = (e: MouseEvent) => {
        if (!volumeRef.current || !videoRef.current) {
          return;
        }

        const { x } = getPointerPosition(volumeRef.current, e);

        if (!isNaN(x)) {
          videoRef.current.volume = x;
          videoRef.current.muted = x > 0 ? false : true;
          void api.start({ volume: `${x * 100}%`, immediate: true });
        }
      };

      document.addEventListener('mousemove', handleVolumeMouseMove, true);
      document.addEventListener('mouseup', handleVolumeMouseUp, true);

      handleVolumeMouseMove(e.nativeEvent);

      e.preventDefault();
      e.stopPropagation();
    },
    [api],
  );

  const handleSeekMouseDown = useCallback(
    (e: React.MouseEvent) => {
      const handleSeekMouseUp = () => {
        document.removeEventListener('mousemove', handleSeekMouseMove, true);
        document.removeEventListener('mouseup', handleSeekMouseUp, true);

        setDragging(false);
        void videoRef.current?.play();
      };

      const handleSeekMouseMove = (e: MouseEvent) => {
        if (!seekRef.current || !videoRef.current) {
          return;
        }

        const { x } = getPointerPosition(seekRef.current, e);
        const newTime = videoRef.current.duration * x;

        if (!isNaN(newTime)) {
          videoRef.current.currentTime = newTime;
          void api.start({ progress: `${x * 100}%`, immediate: true });
        }
      };

      document.addEventListener('mousemove', handleSeekMouseMove, true);
      document.addEventListener('mouseup', handleSeekMouseUp, true);

      setDragging(true);
      videoRef.current?.pause();
      handleSeekMouseMove(e.nativeEvent);

      e.preventDefault();
      e.stopPropagation();
    },
    [setDragging, api],
  );

  const seekBy = (time: number) => {
    if (!videoRef.current) {
      return;
    }

    const newTime = videoRef.current.currentTime + time;

    if (!isNaN(newTime)) {
      videoRef.current.currentTime = newTime;
    }
  };

  const updateVolumeBy = (step: number) => {
    if (!videoRef.current) {
      return;
    }

    const newVolume = videoRef.current.volume + step;

    if (!isNaN(newVolume)) {
      videoRef.current.volume = newVolume;
      videoRef.current.muted = newVolume > 0 ? false : true;
    }
  };

  const handleVideoKeyDown = useCallback(
    (e: React.KeyboardEvent) => {
      // On the video element or the seek bar, we can safely use the space bar
      // for playback control because there are no buttons to press

      if (e.key === ' ') {
        e.preventDefault();
        e.stopPropagation();
        registerHotkeyEvent(setHotkeyEvents, {
          icon: videoRef.current?.paused ? PlayArrowIcon : PauseIcon,
          label: videoRef.current?.paused ? messages.play : messages.pause,
        });
        togglePlay();
      }
    },
    [setHotkeyEvents, togglePlay],
  );

  const handleKeyDown = useCallback(
    (e: React.KeyboardEvent) => {
      const frameTime = 1 / frameRateAsNumber(frameRate);

      switch (e.key) {
        case 'k':
        case ' ':
          e.preventDefault();
          e.stopPropagation();
          registerHotkeyEvent(setHotkeyEvents, {
            icon: videoRef.current?.paused ? PlayArrowIcon : PauseIcon,
            label: videoRef.current?.paused ? messages.play : messages.pause,
          });
          togglePlay();
          break;
        case 'm':
          e.preventDefault();
          e.stopPropagation();
          registerHotkeyEvent(setHotkeyEvents, {
            icon: videoRef.current?.muted ? VolumeUpIcon : VolumeOffIcon,
            label: videoRef.current?.muted ? messages.unmute : messages.mute,
          });
          toggleMute();
          break;
        case 'f':
          e.preventDefault();
          e.stopPropagation();
          registerHotkeyEvent(setHotkeyEvents, {
            icon: isFullscreen() ? FullscreenExitIcon : FullscreenIcon,
            label: isFullscreen()
              ? messages.exit_fullscreen
              : messages.fullscreen,
          });
          toggleFullscreen();
          break;
        case 'j':
        case 'ArrowLeft':
          e.preventDefault();
          e.stopPropagation();
          registerHotkeyEvent(setHotkeyEvents, {
            icon: Replay5Icon,
            label: messages.skipBackward,
          });
          seekBy(-5);
          break;
        case 'l':
        case 'ArrowRight':
          e.preventDefault();
          e.stopPropagation();
          registerHotkeyEvent(setHotkeyEvents, {
            icon: Forward5Icon,
            label: messages.skipForward,
          });
          seekBy(5);
          break;
        case ',':
          e.preventDefault();
          e.stopPropagation();
          seekBy(-frameTime);
          break;
        case '.':
          e.preventDefault();
          e.stopPropagation();
          seekBy(frameTime);
          break;
        case 'ArrowUp':
          e.preventDefault();
          e.stopPropagation();
          registerHotkeyEvent(setHotkeyEvents, {
            icon: VolumeUpIcon,
            label: messages.volumeUp,
          });
          updateVolumeBy(0.15);
          break;
        case 'ArrowDown':
          e.preventDefault();
          e.stopPropagation();
          registerHotkeyEvent(setHotkeyEvents, {
            icon: VolumeDownIcon,
            label: messages.volumeDown,
          });
          updateVolumeBy(-0.15);
          break;
      }

      // If we are in fullscreen mode, we don't want any hotkeys
      // interacting with the UI that's not visible

      if (fullscreen) {
        e.preventDefault();
        e.stopPropagation();

        if (e.key === 'Escape') {
          setHotkeyEvents((events) => [
            ...events,
            {
              key: hotkeyEventId++,
              icon: FullscreenExitIcon,
              label: messages.exit_fullscreen,
            },
          ]);
          exitFullscreen();
        }
      }
    },
    [
      setHotkeyEvents,
      togglePlay,
      toggleFullscreen,
      toggleMute,
      fullscreen,
      frameRate,
    ],
  );

  const handleMouseEnter = useCallback(() => {
    setHovered(true);

    if (hoverTimeoutRef.current) {
      clearTimeout(hoverTimeoutRef.current);
    }

    hoverTimeoutRef.current = setTimeout(() => {
      setHovered(false);
    }, HOVER_FADE_DELAY);
  }, [setHovered]);

  const handleMouseMove = useCallback(() => {
    setHovered(true);

    if (hoverTimeoutRef.current) {
      clearTimeout(hoverTimeoutRef.current);
    }

    hoverTimeoutRef.current = setTimeout(() => {
      setHovered(false);
    }, HOVER_FADE_DELAY);
  }, [setHovered]);

  const handleMouseLeave = useCallback(() => {
    setHovered(false);
  }, [setHovered]);

  const toggleReveal = useCallback(() => {
    if (onToggleVisibility) {
      onToggleVisibility();
    } else {
      setRevealed((value) => !value);
    }
  }, [setRevealed, onToggleVisibility]);

  const handleLoadedData = useCallback(() => {
    if (!videoRef.current) {
      return;
    }

    setDuration(videoRef.current.duration);

    if (typeof startTime !== 'undefined') {
      videoRef.current.currentTime = startTime;
    }

    if (typeof startVolume !== 'undefined') {
      videoRef.current.volume = startVolume;
    }

    if (typeof startMuted !== 'undefined') {
      videoRef.current.muted = startMuted;
    }

    if (startPlaying) {
      void videoRef.current.play();
    }
  }, [setDuration, startTime, startVolume, startMuted, startPlaying]);

  const handleProgress = useCallback(() => {
    if (!videoRef.current) {
      return;
    }

    const lastTimeRange = videoRef.current.buffered.length - 1;

    if (lastTimeRange > -1) {
      void api.start({
        buffer: `${Math.ceil(videoRef.current.buffered.end(lastTimeRange) / videoRef.current.duration) * 100}%`,
      });
    }
  }, [api]);

  const handleVolumeChange = useCallback(() => {
    if (!videoRef.current) {
      return;
    }

    setVolume(videoRef.current.volume);
    setMuted(videoRef.current.muted);

    void api.start({
      volume: `${videoRef.current.muted ? 0 : videoRef.current.volume * 100}%`,
    });

    persistVolume(videoRef.current.volume, videoRef.current.muted);
  }, [api, setVolume, setMuted]);

  const handleOpenVideo = useCallback(() => {
    if (!videoRef.current) {
      return;
    }

    const wasPaused = videoRef.current.paused;

    videoRef.current.pause();

    onOpenVideo?.({
      startTime: videoRef.current.currentTime,
      autoPlay: !wasPaused,
      defaultVolume: videoRef.current.volume,
    });
  }, [onOpenVideo]);

  const handleCloseVideo = useCallback(() => {
    if (!videoRef.current) {
      return;
    }

    videoRef.current.pause();

    onCloseVideo?.();
  }, [onCloseVideo]);

  const handleHotkeyEventDismiss = useCallback(
    ({ key }: HotkeyEvent) => {
      setHotkeyEvents((events) => events.filter((e) => e.key !== key));
    },
    [setHotkeyEvents],
  );

  const progress = Math.min((currentTime / duration) * 100, 100);
  const effectivelyMuted = muted || volume === 0;

  let preload;

  if (startTime || fullscreen || dragging) {
    preload = 'auto';
  } else if (detailed) {
    preload = 'metadata';
  } else {
    preload = 'none';
  }

  // The outer wrapper is necessary to avoid reflowing the layout when going into full screen
  return (
    <div>
      <div /* eslint-disable-line jsx-a11y/click-events-have-key-events */
        role='menuitem'
        className={classNames('video-player', {
          inactive: !revealed,
          detailed,
          fullscreen,
          editable,
        })}
        style={{ aspectRatio }}
        ref={playerRef}
        onMouseEnter={handleMouseEnter}
        onMouseMove={handleMouseMove}
        onMouseLeave={handleMouseLeave}
        onClick={handleClickRoot}
        onKeyDownCapture={handleKeyDown}
        tabIndex={0}
      >
        {blurhash && (
          <Blurhash
            hash={blurhash}
            className={classNames('media-gallery__preview', {
              'media-gallery__preview--hidden': revealed,
            })}
            dummy={!useBlurhash}
          />
        )}

        {(revealed || editable) && (
          <video /* eslint-disable-line jsx-a11y/media-has-caption */
            ref={handleVideoRef}
            src={src}
            poster={preview}
            preload={preload}
            role='button'
            tabIndex={0}
            aria-label={alt}
            title={alt}
            lang={lang}
            onClick={handleClick}
            onKeyDownCapture={handleVideoKeyDown}
            onPlay={handlePlay}
            onPause={handlePause}
            onLoadedData={handleLoadedData}
            onProgress={handleProgress}
            onTimeUpdate={handleTimeUpdate}
            onVolumeChange={handleVolumeChange}
            style={{ width: '100%' }}
          />
        )}

        <HotkeyIndicator
          events={hotkeyEvents}
          onDismiss={handleHotkeyEventDismiss}
        />

        <SpoilerButton
          hidden={revealed || editable}
          sensitive={sensitive ?? false}
          onClick={toggleReveal}
          matchedFilters={matchedFilters}
        />

        {!onCloseVideo &&
          !editable &&
          !fullscreen &&
          !alwaysVisible &&
          revealed && (
            <div
              className={classNames('media-gallery__actions', {
                active: paused || hovered,
              })}
            >
              <button
                className='media-gallery__actions__pill'
                onClick={toggleReveal}
              >
                <FormattedMessage
                  id='media_gallery.hide'
                  defaultMessage='Hide'
                />
              </button>
            </div>
          )}

        <div
          className={classNames('video-player__controls', {
            active: paused || hovered,
          })}
        >
          <div
            className='video-player__seek'
            role='slider'
            aria-valuemin={0}
            aria-valuenow={progress}
            aria-valuemax={100}
            onMouseDown={handleSeekMouseDown}
            onKeyDown={handleVideoKeyDown}
            tabIndex={0}
            ref={seekRef}
          >
            <animated.div
              className='video-player__seek__buffer'
              style={{ width: style.buffer }}
            />
            <animated.div
              className='video-player__seek__progress'
              style={{ width: style.progress }}
            />

            <animated.span
              className={classNames('video-player__seek__handle', {
                active: dragging,
              })}
              style={{ left: style.progress }}
            />
          </div>

          <div className='video-player__buttons-bar'>
            <div className='video-player__buttons left'>
              <button
                type='button'
                title={intl.formatMessage(
                  paused ? messages.play : messages.pause,
                )}
                aria-label={intl.formatMessage(
                  paused ? messages.play : messages.pause,
                )}
                className='player-button'
                onClick={togglePlay}
              >
                <Icon
                  id={paused ? 'play' : 'pause'}
                  icon={paused ? PlayArrowIcon : PauseIcon}
                />
              </button>
              <button
                type='button'
                title={intl.formatMessage(
                  effectivelyMuted ? messages.unmute : messages.mute,
                )}
                aria-label={intl.formatMessage(
                  muted ? messages.unmute : messages.mute,
                )}
                className='player-button'
                onClick={toggleMute}
              >
                <Icon
                  id={effectivelyMuted ? 'volume-off' : 'volume-up'}
                  icon={effectivelyMuted ? VolumeOffIcon : VolumeUpIcon}
                />
              </button>

              <div
                className={classNames('video-player__volume', {
                  active: hovered,
                })}
                role='slider'
                aria-valuemin={0}
                aria-valuenow={effectivelyMuted ? 0 : volume * 100}
                aria-valuemax={100}
                onMouseDown={handleVolumeMouseDown}
                ref={volumeRef}
                tabIndex={0}
              >
                <animated.div
                  className='video-player__volume__current'
                  style={{ width: style.volume }}
                />

                <animated.span
                  className={classNames('video-player__volume__handle')}
                  style={{ left: style.volume }}
                />
              </div>

              {(detailed || fullscreen) && (
                <span className='video-player__time'>
                  <span className='video-player__time-current'>
                    {formatTime(Math.floor(currentTime))}
                  </span>
                  <span className='video-player__time-sep'>/</span>
                  <span className='video-player__time-total'>
                    {formatTime(Math.floor(duration))}
                  </span>
                </span>
              )}
            </div>

            <div className='video-player__buttons right'>
              {!fullscreen && onOpenVideo && (
                <button
                  type='button'
                  title={intl.formatMessage(messages.expand)}
                  aria-label={intl.formatMessage(messages.expand)}
                  className='player-button'
                  onClick={handleOpenVideo}
                >
                  <Icon id='expand' icon={RectangleIcon} />
                </button>
              )}
              {onCloseVideo && (
                <button
                  type='button'
                  title={intl.formatMessage(messages.close)}
                  aria-label={intl.formatMessage(messages.close)}
                  className='player-button'
                  onClick={handleCloseVideo}
                >
                  <Icon id='compress' icon={FullscreenExitIcon} />
                </button>
              )}
              <button
                type='button'
                title={intl.formatMessage(
                  fullscreen ? messages.exit_fullscreen : messages.fullscreen,
                )}
                aria-label={intl.formatMessage(
                  fullscreen ? messages.exit_fullscreen : messages.fullscreen,
                )}
                className='player-button'
                onClick={toggleFullscreen}
              >
                <Icon
                  id={fullscreen ? 'compress' : 'arrows-alt'}
                  icon={fullscreen ? FullscreenExitIcon : FullscreenIcon}
                />
              </button>
            </div>
          </div>
        </div>
      </div>
    </div>
  );
};

// eslint-disable-next-line import/no-default-export
export default Video;
