import React from "react";
import { Animated, Easing, View, TouchableWithoutFeedback, ScrollView, StyleSheet, Dimensions, I18nManager } from "react-native";
import { APPROX_STATUSBAR_HEIGHT } from "../../constants";
import { withTheme } from "../../core/theming";
import Portal from "../Portal/Portal";
import Surface from "../Surface";
import MenuItem from "./MenuItem";
// Minimum padding between the edge of the screen and the menu
const SCREEN_INDENT = 8;
// From https://material.io/design/motion/speed.html#duration
const ANIMATION_DURATION = 250;
// From the 'Standard easing' section of https://material.io/design/motion/speed.html#easing
const EASING = Easing.bezier(0.4, 0, 0.2, 1);
// Padding between the menu and the anchor
const SPACING_FROM_ANCHOR = 8;
const Menu = _ref => {
  let {
    visible,
    anchor,
    theme,
    children,
    contentStyle,
    style,
    statusBarHeight = APPROX_STATUSBAR_HEIGHT,
    overlayAccessibilityLabel = "Close menu",
    onDismiss,
    keyboardShouldPersistTaps
  } = _ref;
  const windowLayout = Dimensions.get("window");
  let additionalVerticalValue = React.useRef(0).current;
  const positionTransforms = React.useRef([]);
  const anchorRef = React.useRef(null);
  const [anchorMeasurements, setAnchorMeasurements] = React.useState({
    x: 0,
    y: 0,
    width: 0,
    height: 0
  });
  const [menuMeasurements, setMenuMeasurements] = React.useState({
    x: 0,
    y: 0,
    width: 0,
    height: 0
  });
  const [scrollableMenuHeightState, setScrollableMenuHeight] = React.useState(0);
  const menuRef = React.useRef(null);
  const [rendered, setRendered] = React.useState(visible);
  if (visible && !rendered) {
    setRendered(true);
  }
  React.useEffect(() => {
    if (!visible && rendered) {
      setRendered(false);
    }
  }, [visible]);
  React.useEffect(() => {
    let left = anchorMeasurements.x;
    let top = anchorMeasurements.y;
    if (left === 0 && top === 0) return;
    if (!rendered)
      //don't run if the menu has already been positioned
      return;
    additionalVerticalValue = anchorMeasurements.height;
    // Check if menu fits horizontally and if not align it to right.
    if (left <= windowLayout.width - menuMeasurements.width - SCREEN_INDENT) {
      // Check if menu position has enough space from left side
      if (left < SCREEN_INDENT) {
        left = SCREEN_INDENT;
      }
    } else {
      left += anchorMeasurements.width - menuMeasurements.width;
      const right = left + menuMeasurements.width;
      // Check if menu position has enough space from right side
      if (right > windowLayout.width - SCREEN_INDENT) {
        left = windowLayout.width - SCREEN_INDENT - menuMeasurements.width;
      }
    }

    // If the menu is larger than available vertical space, calculate the height of scrollable view
    let scrollableMenuHeight = 0;

    // Check if the menu should be scrollable
    if (
    // Check if the menu overflows from bottom side
    top >= windowLayout.height - menuMeasurements.height - 2 * SCREEN_INDENT - additionalVerticalValue &&
    // And bottom side of the screen has more space than top side
    top <= windowLayout.height - top) {
      // Scrollable menu should be below the anchor (expands downwards)
      scrollableMenuHeight = windowLayout.height - top - 2 * SCREEN_INDENT - additionalVerticalValue;
    } else if (
    // Check if the menu overflows from bottom side
    top >= windowLayout.height - menuMeasurements.height - 2 * SCREEN_INDENT - additionalVerticalValue &&
    // And top side of the screen has more space than bottom side
    top >= windowLayout.height - top &&
    // And menu overflows from top side
    top <= menuMeasurements.height - anchorMeasurements.height + 2 * SCREEN_INDENT) {
      // Scrollable menu should be above the anchor (expands upwards)
      scrollableMenuHeight = top - 4 * SCREEN_INDENT + additionalVerticalValue - statusBarHeight;
    }

    // Scrollable menu max height
    scrollableMenuHeight = scrollableMenuHeight > windowLayout.height - 3 * SCREEN_INDENT ? windowLayout.height - 3 * SCREEN_INDENT : scrollableMenuHeight;

    // Menu is typically positioned below the element that generates it
    // So first check if it fits below the anchor (expands downwards)
    if (
    // Check if menu fits vertically
    top <= windowLayout.height - menuMeasurements.height - SCREEN_INDENT - additionalVerticalValue ||
    // Or if the menu overflows from bottom side
    top >= windowLayout.height - menuMeasurements.height - SCREEN_INDENT - additionalVerticalValue &&
    // And bottom side of the screen has more space than top side
    top <= windowLayout.height - top) {
      top += additionalVerticalValue + SCREEN_INDENT;
      // Check if menu position has enough space from top side
      if (top < SCREEN_INDENT) {
        top = SCREEN_INDENT;
      }
    } else {
      top += -(scrollableMenuHeight || menuMeasurements.height) - SCREEN_INDENT;
      const bottom = top + (scrollableMenuHeight || menuMeasurements.height) + 2 * SCREEN_INDENT;

      // Check if menu position has enough space from bottom side
      if (bottom > windowLayout.height - 2 * SCREEN_INDENT) {
        top = scrollableMenuHeight === windowLayout.height - 2 * SCREEN_INDENT ? -SCREEN_INDENT * 2 : windowLayout.height - menuMeasurements.height - 2 * SCREEN_INDENT - additionalVerticalValue;
      }
    }
    setMenuMeasurements(state => ({
      ...state,
      x: left,
      y: top
    }));
    setScrollableMenuHeight(scrollableMenuHeight);
  }, [anchorMeasurements.x, anchorMeasurements.y, menuMeasurements.width
  // menuMeasurements.height,
  ]);

  const isCoordinate = anchor => ! /*#__PURE__*/React.isValidElement(anchor) && typeof (anchor === null || anchor === void 0 ? void 0 : anchor.x) === "number" && typeof (anchor === null || anchor === void 0 ? void 0 : anchor.y) === "number";
  const positionStyle = {
    top: isCoordinate(anchor) ? anchorMeasurements.y : menuMeasurements.y,
    ...(I18nManager.getConstants().isRTL ? {
      right: menuMeasurements.x
    } : {
      left: menuMeasurements.x
    })
  };
  const shadowMenuContainerStyle = {
    borderRadius: theme.roundness,
    ...(scrollableMenuHeightState ? {
      height: scrollableMenuHeightState
    } : {})
  };
  return /*#__PURE__*/React.createElement(View, {
    onLayout: e => {
      anchorRef.current.measureInWindow((x, y, width, height) => {
        setAnchorMeasurements({
          x,
          y,
          width,
          height
        });
      });
    },
    ref: anchorRef,
    collapsable: false,
    style: {
      width: "100%"
    }
  }, isCoordinate(anchor) ? null : anchor, rendered ? /*#__PURE__*/React.createElement(Portal, null, /*#__PURE__*/React.createElement(TouchableWithoutFeedback, {
    accessibilityLabel: overlayAccessibilityLabel,
    accessibilityRole: "button",
    onPress: onDismiss
  }, /*#__PURE__*/React.createElement(View, {
    style: [StyleSheet.absoluteFill]
  })), /*#__PURE__*/React.createElement(Surface, {
    ref: menuRef,
    collapsable: false,
    accessibilityViewIsModal: visible,
    style: [styles.wrapper, positionStyle, style],
    pointerEvents: visible ? "box-none" : "none",
    onAccessibilityEscape: onDismiss,
    onLayout: e => {
      if (anchorRef) {
        anchorRef.current.measureInWindow((x, y, width, height) => {
          if (anchorMeasurements.x !== x || anchorMeasurements.y !== y || anchorMeasurements.width !== width || anchorMeasurements.height !== height) {
            setAnchorMeasurements({
              x,
              y,
              width,
              height
            });
          }
        });
      }
      if (e.nativeEvent.layout.width !== menuMeasurements.width || e.nativeEvent.layout.height !== menuMeasurements.height) {
        setMenuMeasurements({
          ...e.nativeEvent.layout
        });
      }
    }
  }, /*#__PURE__*/React.createElement(Animated.View, null, /*#__PURE__*/React.createElement(Surface, {
    style: [styles.shadowMenuContainer, shadowMenuContainerStyle, contentStyle, {
      opacity: 1
    }]
  }, scrollableMenuHeightState && /*#__PURE__*/React.createElement(ScrollView, {
    keyboardShouldPersistTaps: keyboardShouldPersistTaps
  }, children) || /*#__PURE__*/React.createElement(React.Fragment, null, children))))) : null);
};
Menu.Item = MenuItem;
const styles = StyleSheet.create({
  wrapper: {
    position: "absolute",
    borderRadius: 12,
    elevation: 4
  },
  shadowMenuContainer: {
    opacity: 0,
    paddingVertical: 8
  }
});
export default withTheme(Menu);
//# sourceMappingURL=Menu.js.map