import * as React from "react";
import { useRef, useState, useReducer, useEffect } from "react";
import { View, Animated, Easing } from "react-native";
import Video, {
  VideoProperties,
  OnProgressData,
  OnLoadData,
} from "react-native-video";
import { VideoPlayerNativeContainer } from "./styed";

import { videoPlayerReducer } from "./video-player-reducer";
import Overlay from "./components/overlay";
import Controls from "./components/controls";
import { Gateway } from "react-gateway";

type VideoPlayerProps = {} & VideoProperties;
const absoluteStyle = {
  width: "100%",
  height: "100%",
  top: 0,
  bottom: 0,
  position: "absolute",
};
function VideoPlayerNative(props: VideoPlayerProps) {
  const [
    { isPaused, progress, duration, progressLayout, fullScreenMode },
    dispatch,
  ] = useReducer(videoPlayerReducer, {
    isPaused: false,
    duration: 0,
    progressLayout: {},
  });
  const videoProgressRef = useRef<number | undefined>();
  const showControlsRef = useRef<any | undefined>(undefined);
  const [controlsShow, setControlsShow] = useState(false);
  const opacityAnimation = useRef(new Animated.Value(0)).current;
  const videoPlayerRef = useRef<Video | null>();

  function pauseStop() {
    if (!isPaused) dispatch({ type: "pause" });
    else dispatch({ type: "play" });
  }

  function handleProgress(incomingProgress: OnProgressData) {
    dispatch({
      type: "progress",
      payload: { progress: incomingProgress.currentTime },
    });
  }

  function forward() {
    videoPlayerRef.current?.seek((progress || 0) + 15);
  }

  function backward() {
    videoPlayerRef.current?.seek((progress || 0) - 15);
  }

  function handleLoad(meta: OnLoadData) {
    if (videoProgressRef.current) {
      videoPlayerRef.current?.seek(videoProgressRef.current || 0);
      videoProgressRef.current = undefined;
    } else dispatch({ type: "loaded", payload: { duration: meta.duration } });
  }

  function handleProgressPress(e: any) {
    const position = e.nativeEvent.locationX;
    const progress = (position / progressLayout.width) * duration;
    dispatch({ type: "progress", payload: { progress } });
    videoPlayerRef.current?.seek(progress);
  }

  function setProgressLayout(e: any) {
    dispatch({
      type: "set-progress-layout",
      payload: { layout: e.nativeEvent.layout },
    });
  }

  function switchFullScreen() {
    videoProgressRef.current = progress;
    dispatch({ type: "switch-screen-mode" });
  }

  function showControls(e?: any) {
    if (showControlsRef.current) clearTimeout(showControlsRef.current);
    const hidde = () => {
      Animated.timing(opacityAnimation, {
        useNativeDriver: false,
        toValue: 0,
        duration: 300,
        easing: Easing.bezier(0.16, 1, 0.3, 1),
      }).start(() => {
        setControlsShow(false);
      });
    };

    if (!e) {
      showControlsRef.current = setTimeout(hidde, 3000);
      return;
    }

    if (!controlsShow) {
      setControlsShow(true);
      Animated.timing(opacityAnimation, {
        useNativeDriver: false,
        toValue: 1,
        duration: 300,
        easing: Easing.bezier(0.16, 1, 0.3, 1),
      }).start(() => {
        showControlsRef.current = setTimeout(hidde, 3000);
      });
    } else {
      hidde();
    }
  }

  const showControlsMiddleware = (fn: any) => (e?: any) => {
    showControls();
    fn(e);
  };

  const render = (
    <VideoPlayerNativeContainer activeOpacity={1} onPress={showControls}>
      <View>
        <Video
          {...props}
          style={{ width: "100%", height: "100%" }}
          fullscreen={fullScreenMode}
          ref={(r) => {
            videoPlayerRef.current = r;
          }}
          paused={isPaused}
          controls={false}
          onProgress={handleProgress}
          onLoad={handleLoad}
        />

        <>
          <Animated.View
            style={{
              opacity: opacityAnimation,
              ...absoluteStyle,
              top: controlsShow ? 0 : "100%",
            }}
          >
            <Overlay />
            <Controls
              duration={duration}
              isPaused={isPaused}
              onBackward={showControlsMiddleware(backward)}
              onFullscreenMode={showControlsMiddleware(switchFullScreen)}
              onForward={showControlsMiddleware(forward)}
              onHandleProgressPress={showControlsMiddleware(
                handleProgressPress
              )}
              onPauseStop={showControlsMiddleware(pauseStop)}
              onSetProgressLayout={showControlsMiddleware(setProgressLayout)}
              progress={progress || 1}
            />
          </Animated.View>
        </>
      </View>
    </VideoPlayerNativeContainer>
  );

  if (!fullScreenMode) return render;
  else return <Gateway into="global">{render}</Gateway>;
}

/*
 */

export default VideoPlayerNative;
