import * as React from 'react';
import {
  RefObject, FC, useContext, MouseEvent, KeyboardEvent, useRef, useEffect, useState,
} from 'react';
import { style } from 'typestyle';
import { onKeyDownEventCallback } from '../../../../../utils/onKeyDown';
import ThumbnailPlayIcon from '../../../../Icons/ThumbnailPlay';
import UserName from '../../../../UserName';
import MuteButton from '../../MuteButton';
import VideoDurationBar from '../../VideoDurationBar';
import { StoreContext } from '../../../../../services/store';
import { pillBackgroundColor, pillFontColor, pillZIndex } from '../../../../consts';

interface VideoContentProps {
  video: string;
  pause: boolean;
  onPause: () => void;
  onPlay: () => void;
  videoRef: RefObject<HTMLVideoElement>;
  contentClass: string;
  source?: string;
  username?: string;
  isMuted?: boolean;
  toggleMute?: () => void;
  showDurationBar?: boolean;
  showUsernamePill?: boolean;
}

const VideoContent: FC<VideoContentProps> = ({
  video,
  pause,
  onPause,
  onPlay,
  videoRef,
  contentClass,
  source,
  username,
  isMuted,
  toggleMute,
  showDurationBar,
  showUsernamePill,
}) => {
  const context = useContext(StoreContext);
  const playButtonRef = useRef<HTMLDivElement>(null);
  const pauseButtonRef = useRef<HTMLDivElement>(null);
  const previousPauseState = useRef<boolean>(pause);
  const [currentTime, setCurrentTime] = useState(0);
  const [duration, setDuration] = useState(0);

  // Transfer focus when toggling between play and pause
  useEffect(() => {
    if (previousPauseState.current !== pause) {
      if (pause && playButtonRef.current) {
        playButtonRef.current.focus();
      } else if (!pause && pauseButtonRef.current) {
        pauseButtonRef.current.focus();
      }
      previousPauseState.current = pause;
    }
  }, [pause]);

  const handleTimeUpdate = () => {
    const vid = videoRef.current;
    if (!vid || !vid.duration) return;
    setCurrentTime(vid.currentTime);
    setDuration(vid.duration);
  };

  const handlePlay = (e: MouseEvent<HTMLDivElement> | KeyboardEvent<HTMLDivElement>) => {
    if (context.post) {
      context.triggerEvent(
        'videoPlayed',
        {
          originalEvent: e.nativeEvent as Event,
          post: context.post,
        },
        context.data.id,
      );
    }
    onPlay();
  };

  const handlePause = (e: MouseEvent<HTMLDivElement> | KeyboardEvent<HTMLDivElement>) => {
    e.stopPropagation();
    onPause();
  };

  return (
    <>
      <div style={containerStyle} aria-hidden='true'>
        <video
          ref={videoRef}
          className={`${styles.videoContent} ${contentClass}`}
          controls={false}
          muted={isMuted}
          playsInline
          onEnded={onPause}
          onTimeUpdate={showDurationBar ? handleTimeUpdate : undefined}
          aria-hidden='true'
        >
          <source src={video} type='video/mp4' />
        </video>
      </div>
      {!pause ? (
        <div
          ref={pauseButtonRef}
          className={styles.videoOverlay}
          onClick={handlePause}
          onKeyDown={(e) => onKeyDownEventCallback(e, handlePause)}
          tabIndex={0}
          role='button'
          aria-label='pause video'
        />
      ) : null}
      {pause ? (
        <div
          ref={playButtonRef}
          className={`${styles.playButton} ${context.config.classPrefix}-postviewer-play-video-btn`}
          onClick={handlePlay}
          onKeyDown={(e) => onKeyDownEventCallback(e, handlePlay)}
          tabIndex={0}
          role='button'
          aria-label={
            source && username ? `Play video created on ${source} by ${username}.` : 'Play video'
          }
        >
          <ThumbnailPlayIcon style={{ flex: 1 }} />
        </div>
      ) : null}
      {showUsernamePill ? (
        <div className={styles.userNameTopLeft} aria-hidden='true'>
          <UserName
            color={pillFontColor}
            padding='10px 12px'
            backgroundColor={pillBackgroundColor}
          />
        </div>
      ) : null}
      {toggleMute !== undefined && isMuted !== undefined ? (
        <div className={styles.muteWrapper}>
          <MuteButton isMuted={isMuted} toggleMute={toggleMute} />
        </div>
      ) : null}
      {showDurationBar && !pause ? (
        <VideoDurationBar currentTime={currentTime} duration={duration} />
      ) : null}
    </>
  );
};

const containerStyle = {
  position: 'relative' as const,
  width: '100%',
  height: '100%',
  display: 'flex' as const,
};

const styles = {
  videoContent: style({
    maxWidth: '100%',
    maxHeight: '100%',
    backgroundSize: 'cover',
    backgroundPosition: 'center',
    overflow: 'hidden',
  }),
  videoOverlay: style({
    position: 'absolute',
    top: 0,
    left: 0,
    bottom: 0,
    right: 0,
    cursor: 'pointer',
    outline: 'none',
    zIndex: 2,
    $nest: {
      '&:focus-visible': {
        outline: '2px solid rgba(255, 255, 255, 0.8)',
        outlineOffset: '-4px',
      },
    },
  }),
  playButton: style({
    position: 'absolute',
    cursor: 'pointer',
    top: 0,
    left: 0,
    bottom: 0,
    right: 0,
    display: 'flex',
    flexDirection: 'column',
    alignItems: 'center',
  }),
  userNameTopLeft: style({
    position: 'absolute',
    top: 16,
    left: 16,
    zIndex: pillZIndex,
  }),
  muteWrapper: style({
    position: 'absolute',
    top: 16,
    right: 16,
    zIndex: pillZIndex,
  }),
};

export default VideoContent;
