import { VisuallyHidden } from '@ariakit/react';
import { getClassNames } from '@websolutespa/bom-core';
import { useIntersectionObserver, useLayout, useMounted, useReducedMotionLocal } from '@websolutespa/bom-mixer-hooks';
import { memo, useCallback, useEffect, useId, useRef, useState } from 'react';
import styled from 'styled-components';
import { Button } from '../button/button';
import { UIStyledComponentProps } from '../types';
import { IMediaItemProps } from './media-items';

const StyledMediaVideo = styled.video`
  max-width: 100%;
  // height: auto;
  user-select: none;
  color: transparent;

  &.video {
    &--muted {
      &::cue {
        background-color: transparent;
        background-image: none;
        color: transparent;
        font-size: 0;
      }
    }
  }
`;

const StyledButton = styled(Button)`
  position: absolute;
  top: 0;
  left: 0;
  width: 100%;
  height: 100%;
  z-index: 1;
`;

export type MediaVideoProps = UIStyledComponentProps<IMediaItemProps, 'video'>;

const MediaVideo_ = ({ className, onLoaded, canLoad = true, src: mediaSrc, mimeType = 'video/mp4', ...props }: MediaVideoProps) => {
  const videoRef = useRef<HTMLVideoElement>(null);
  const { locale } = useLayout();
  const [src, setSrc] = useState<string>();

  useEffect(() => {
    if (videoRef.current && src) {
      const video = videoRef.current;
      const onReadyState = () => {
        if (
          typeof onLoaded === 'function' &&
          videoRef.current &&
          videoRef.current.readyState &&
          videoRef.current.readyState >= 2
        ) {
          onLoaded(videoRef as React.RefObject<HTMLVideoElement>);
        }
      };
      if (
        video.readyState &&
        video.readyState >= 2
      ) {
        onReadyState();
      } else {
        video.addEventListener('loadeddata', onReadyState);
        return () => {
          video.removeEventListener('loadeddata', onReadyState);
        };
      }
    }
    return () => { };
  }, [videoRef, onLoaded, src]);

  const play = useCallback(() => {
    if (!videoRef.current) {
      return;
    }
    videoRef.current.play();
  }, [videoRef]);

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

  const isIntersecting = useIntersectionObserver(videoRef, {
    threshold: 0,
    root: null,
    rootMargin: '0px',
  });

  const shouldLoad = isIntersecting && canLoad;

  // handle intersection
  useEffect(() => {
    if (shouldLoad && src !== mediaSrc) {
      setSrc(mediaSrc);
    }
  }, [shouldLoad, src, mediaSrc]);

  const mounted = useMounted();
  const id = useId();
  const { reducedMotionLocal, toggleReducedMotionLocal, setReducedMotionLocal } = useReducedMotionLocal();

  const shouldPlay = shouldLoad && mounted && !reducedMotionLocal;

  // handle shouldPlay
  useEffect(() => {
    if (shouldPlay) {
      play();
    } else {
      pause();
    }
  }, [shouldPlay, play]);

  const classNames = getClassNames(className, 'video', 'video--muted');
  return (
    <>
      {mounted && (
        <StyledButton
          aria-controls={id}
          aria-pressed={!reducedMotionLocal}
          onClick={() => toggleReducedMotionLocal()}
          onBlur={() => setReducedMotionLocal(true)}
        >
          <VisuallyHidden>
            {reducedMotionLocal ? 'Play' : 'Pause'}
          </VisuallyHidden>
        </StyledButton>
      )}
      <StyledMediaVideo
        ref={videoRef}
        id={id}
        className={classNames}
        autoPlay={shouldPlay} muted={true} loop={true} playsInline={true}
        {...props}
        {...(mimeType ? {} : { src })}
      >
        {src && (
          <>
            {mimeType && (
              <source src={src} type={mimeType}></source>
            )}
            {locale && (
              <track
                src={`/captions.vtt?locale=${locale}&title=${props.title}`}
                kind="captions"
                srcLang={locale}
                label="Video Captions"
              ></track>
            )}
          </>
        )}
      </StyledMediaVideo>
    </>
  );
};

export const MediaVideo = memo(MediaVideo_);
