'use client';

import React, { useState, useEffect, useRef } from 'react';
import breakpoints from './breakpoints';

export interface ResponsiveVideoProps
  extends React.VideoHTMLAttributes<HTMLVideoElement> {
  src: string;
  /** first match in the array will be selected
   * media should be a valid media query or
   * a key from breakpoints object
   */
  srcSet?: {
    src: string;
    media: string;
  }[];
  /** auto plays video source */
  autoPlay?: boolean;
  /** If autoplay fails and if there is a fallback,
   * display this fallback element */
  autoPlayFallback?: React.ReactNode;
}

export const ResponsiveVideo = ({
  src,
  srcSet,
  autoPlay,
  autoPlayFallback,
  ...rest
}: ResponsiveVideoProps) => {
  const [isAutoPlayFailed, setIsAutoPlayFailed] = useState(false);
  const [currentSrc, setCurrentSrc] = useState(src);
  const videoRef = useRef<HTMLVideoElement>(null);

  useEffect(() => {
    const handleResize = () => {
      /** find the set that matches current media query */
      const matchedSet = srcSet?.find(
        ({ media }) => window.matchMedia(breakpoints[media] || media).matches
      );
      /* set the current src to the matched set or the default src */
      setCurrentSrc(matchedSet?.src || src);
    };
    /* call handleResize on mount */
    handleResize();
    /* add resize event listener to window */
    window.addEventListener('resize', handleResize);
    /* remove event listener on unmount */
    return () => window.removeEventListener('resize', handleResize);
  }, [src, srcSet]);

  useEffect(() => {
    async function play() {
      try {
        /** If user prefers reduced motion,
         * throw an error and stop autoplay
         */
        const prefersReducedMotion = window.matchMedia(
          '(prefers-reduced-motion: reduce)'
        );

        if (prefersReducedMotion.matches) {
          throw new Error('User prefers reduced motion');
        } else {
          /* if autoplay is true, play the video */
          autoPlay && (await videoRef?.current?.play());
        }
      } catch (error: any) {
        /* AbortError happens when source is changed in runtime,
         if error is not AbortError, mark autoPlay as failed
         */
        if (error.name !== 'AbortError') {
          console.error(error);
          /* if play failed, report that autoplay has failed */
          setIsAutoPlayFailed(true);
        }
      }
    }
    play();
  }, [autoPlay, currentSrc]);

  return isAutoPlayFailed && autoPlayFallback ? (
    autoPlayFallback
  ) : (
    <video ref={videoRef} src={currentSrc} {...rest} />
  );
};

export default ResponsiveVideo;
