import React, { useLayoutEffect } from "react";

import {
  allowedOrientationsForScreen,
  ORIENTATIONS,
  getOrientation,
  useGetScreenOrientation,
} from "@applicaster/zapp-react-native-utils/appUtils/orientationHelper";
import { usePrevious } from "@applicaster/zapp-react-native-utils/reactHooks/utils";
import { usePickFromState } from "@applicaster/zapp-react-native-redux/hooks";
import { findPluginByType } from "@applicaster/zapp-react-native-utils/pluginUtils";
import { useIsTablet } from "@applicaster/zapp-react-native-utils/reactHooks";

import { ZappHookModalContext } from "../../Contexts";
import { HookModalContextT } from "../../Contexts/ZappHookModalContext";

/**
 * This function calls the native module needed to set orientation
 * @param {ORIENTATIONS} orientation desired orientation
 */
function setOrientation(orientation: ORIENTATIONS) {
  allowedOrientationsForScreen(orientation);
}

type OrientationHookArgs = {
  screenData: {};
};

// Current device orienatation state, can not be inside ref,
// because ref lifetime connected to components (i.e. we lose state)
let current = null;

// Override function we use until player screen will start to provide orientation
// in a generic way as other screens
const getPlayerOrientation = ({ screenData, plugins, screenOrientation }) => {
  if (!screenData) {
    return null;
  }

  const isPlayer =
    screenData.plugin_type === "player" || screenData.screenType === "playable";

  if (!isPlayer) {
    return null;
  }

  if (screenOrientation) {
    // Prefer layout screen orientation
    return screenOrientation;
  }

  const player = findPluginByType("player", plugins, {
    returnFullObject: true,
  });

  const playerPluginOrientation = getOrientation(
    player?.configuration?.screen_orientation
  );

  return playerPluginOrientation || ORIENTATIONS.landscapeSensor;
};

export function useNewOrientationForScreenData({
  screenData,
}: OrientationHookArgs) {
  const isTablet = useIsTablet();

  const { appData, plugins } = usePickFromState(["appData", "plugins"]);
  const isTabletPortrait = appData?.isTabletPortrait;
  const isLandscapeTablet = isTablet && !isTabletPortrait;

  const screenOrientation = useGetScreenOrientation(screenData);

  current =
    current ||
    (isLandscapeTablet ? ORIENTATIONS.landscapeSensor : ORIENTATIONS.portrait);

  return isLandscapeTablet
    ? ORIENTATIONS.landscapeSensor
    : getPlayerOrientation({ screenData, plugins, screenOrientation }) ||
        screenOrientation;
}

type Props = {
  screenData: {
    screen: {};
  };
  isActive: boolean;
};

export function useScreenOrientationHandler({ screenData, isActive }: Props) {
  const { isHooksExecutionInProgress } = React.useContext<HookModalContextT>(
    ZappHookModalContext.ReactContext
  );

  const prevIsActive = usePrevious(isActive);

  const newOrientation = useNewOrientationForScreenData({
    screenData: screenData.screen,
  });

  useLayoutEffect(() => {
    // Null means screen does not have orientation preference, so we can skip rotate
    if (!newOrientation) {
      return;
    }

    // If modal hook presented we need to skip
    // Change orientation for presenter screen
    if (isHooksExecutionInProgress) {
      return;
    }

    if (!prevIsActive && isActive && newOrientation !== current) {
      current = newOrientation;

      setOrientation(newOrientation);
    }
  }, [newOrientation, isHooksExecutionInProgress, prevIsActive, isActive]);
}

export function useOrientationHandler({ screenData }: OrientationHookArgs) {
  const newOrientation = useNewOrientationForScreenData({ screenData });

  useLayoutEffect(() => {
    // Null means screen does not have orientation preference, so we can skip rotate
    if (!newOrientation) {
      return;
    }

    if (newOrientation !== current) {
      current = newOrientation;

      setOrientation(newOrientation);
    }
  }, [newOrientation]);
}
