import React from "react";
import { Animated, StyleSheet } from "react-native";

import { useNavigation } from "@applicaster/zapp-react-native-utils/reactHooks";
import { PanGestureHandler, State } from "react-native-gesture-handler";

import { PlayerContainerContext } from "@applicaster/zapp-react-native-ui-components/Components/PlayerContainer/PlayerContainerContext";
import {
  useModalAnimationContext,
  PlayerAnimationStateEnum,
} from "@applicaster/zapp-react-native-ui-components/Components/VideoModal/ModalAnimation";
import { isTV } from "@applicaster/zapp-react-native-utils/reactUtils";

const generalStyles = StyleSheet.create({
  container: {
    flex: 1,
    width: "100%",
    position: "absolute",
    zIndex: 201,
  },
});

type Props = {
  children: React.ReactNode;
};

export const AnimatedVideoPlayer = ({ children }: Props) => {
  const {
    playerAnimationState,
    setPlayerAnimationState,
    animatedValues: { translateYOffset, dragVideoPlayerY, lastScrollY },
    lastScrollYValue,
    modalSnapPoints,
    lastSnap,
    setLastSnap,
    resetPlayerAnimationState,
    setStartComponentsAnimation,
  } = useModalAnimationContext();

  const {
    videoModalState: { mode: videoModalMode },
  } = useNavigation();

  const { isLanguageOverlayVisible, isSeekBarTouch } = React.useContext(
    PlayerContainerContext
  );

  const isMaximazedModal = videoModalMode === "MAXIMIZED";
  const isMinimizedModal = videoModalMode === "MINIMIZED";

  const isNotMinimizeMaximazeAnimation =
    playerAnimationState !== PlayerAnimationStateEnum.minimize &&
    playerAnimationState !== PlayerAnimationStateEnum.maximize;

  const isEnablePanGesture =
    !isLanguageOverlayVisible &&
    isNotMinimizeMaximazeAnimation &&
    !isSeekBarTouch &&
    (isMaximazedModal || isMinimizedModal);

  const onGestureEvent = Animated.event(
    [{ nativeEvent: { translationY: dragVideoPlayerY } }],
    { useNativeDriver: true }
  );

  const onHandlerStateChange = React.useCallback(
    ({ nativeEvent }) => {
      if (nativeEvent.oldState === State.ACTIVE) {
        // eslint-disable-next-line prefer-const
        const { velocityY, translationY } = nativeEvent;
        const preparedTranslationY = Math.abs(translationY);
        const dragToss = 0.05;

        if (videoModalMode === "MAXIMIZED") {
          if (translationY > 0) {
            const endOffsetY =
              lastSnap + preparedTranslationY + dragToss * velocityY + 200;

            let destSnapPoint = modalSnapPoints[0];

            for (const snapPoint of modalSnapPoints) {
              const distFromSnap = Math.abs(snapPoint - endOffsetY);

              if (distFromSnap < Math.abs(destSnapPoint - endOffsetY)) {
                destSnapPoint = snapPoint;
              }
            }

            setLastSnap(destSnapPoint);

            if (destSnapPoint === modalSnapPoints[0]) {
              setPlayerAnimationState(PlayerAnimationStateEnum.maximize);
            } else {
              lastScrollY.setValue(0);
              lastScrollYValue.current = 0;
              setPlayerAnimationState(PlayerAnimationStateEnum.minimize);
            }
          }
        } else if (videoModalMode === "MINIMIZED") {
          if (translationY < 0) {
            // from mini to full
            setLastSnap(modalSnapPoints[0]);

            translateYOffset.setValue(
              modalSnapPoints[1] - preparedTranslationY
            );

            setPlayerAnimationState(PlayerAnimationStateEnum.maximize);
          } else {
            resetPlayerAnimationState();
          }
        }
      }
    },
    [lastSnap, modalSnapPoints, videoModalMode]
  );

  React.useEffect(() => {
    const dragVideoPlayerYListenerId = dragVideoPlayerY.addListener(
      ({ value }) => {
        if (
          (isMinimizedModal && value >= 0) ||
          (isMaximazedModal && value <= 0)
        ) {
          if (playerAnimationState === PlayerAnimationStateEnum.drag_player) {
            translateYOffset.setValue(
              modalSnapPoints[isMinimizedModal ? 1 : 0]
            );
          }
        } else {
          const preparedValue = Math.round(Math.abs(value));

          if (
            preparedValue > 0 &&
            playerAnimationState !== PlayerAnimationStateEnum.drag_scroll
          ) {
            if (playerAnimationState !== PlayerAnimationStateEnum.drag_player) {
              isMinimizedModal && setStartComponentsAnimation(true);
              setPlayerAnimationState(PlayerAnimationStateEnum.drag_player);
            }

            translateYOffset.setValue(
              isMaximazedModal
                ? preparedValue
                : modalSnapPoints[1] - preparedValue
            );
          }
        }
      }
    );

    return () => {
      dragVideoPlayerY.removeListener(dragVideoPlayerYListenerId);
    };
  }, [playerAnimationState, isMinimizedModal, isMaximazedModal]);

  return (
    <PanGestureHandler
      enabled={isEnablePanGesture}
      onGestureEvent={onGestureEvent}
      onHandlerStateChange={onHandlerStateChange}
    >
      <Animated.View style={generalStyles.container}>{children}</Animated.View>
    </PanGestureHandler>
  );
};

export const AnimatedVideoPlayerComponent = ({ children }: Props) => {
  const {
    videoModalState: { visible },
  } = useNavigation();

  const Component = !isTV() && visible ? AnimatedVideoPlayer : React.Fragment;

  return <Component>{children}</Component>;
};
