/**
 * Copyright (c) Meta Platforms, Inc. and affiliates.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 *
 * 
 */

import { getModality } from '../modality';
import useEvent from '../useEvent';
import useLayoutEffect from '../useLayoutEffect';

/**
 * Types
 */

/**
 * Implementation
 */

var emptyObject = {};
var opts = {
  passive: true
};
var lockEventType = 'react-gui:hover:lock';
var unlockEventType = 'react-gui:hover:unlock';
var supportsPointerEvent = () => !!(typeof window !== 'undefined' && window.PointerEvent != null);
function dispatchCustomEvent(target, type, payload) {
  var event = document.createEvent('CustomEvent');
  var _ref = payload || emptyObject,
    _ref$bubbles = _ref.bubbles,
    bubbles = _ref$bubbles === void 0 ? true : _ref$bubbles,
    _ref$cancelable = _ref.cancelable,
    cancelable = _ref$cancelable === void 0 ? true : _ref$cancelable,
    detail = _ref.detail;
  event.initCustomEvent(type, bubbles, cancelable, detail);
  target.dispatchEvent(event);
}

// This accounts for the non-PointerEvent fallback events.
function getPointerType(event) {
  var pointerType = event.pointerType;
  return pointerType != null ? pointerType : getModality();
}
export default function useHover(targetRef, config) {
  var contain = config.contain,
    disabled = config.disabled,
    onHoverStart = config.onHoverStart,
    onHoverChange = config.onHoverChange,
    onHoverUpdate = config.onHoverUpdate,
    onHoverEnd = config.onHoverEnd;
  var canUsePE = supportsPointerEvent();
  var addMoveListener = useEvent(canUsePE ? 'pointermove' : 'mousemove', opts);
  var addEnterListener = useEvent(canUsePE ? 'pointerenter' : 'mouseenter', opts);
  var addLeaveListener = useEvent(canUsePE ? 'pointerleave' : 'mouseleave', opts);
  // These custom events are used to implement the "contain" prop.
  var addLockListener = useEvent(lockEventType, opts);
  var addUnlockListener = useEvent(unlockEventType, opts);
  useLayoutEffect(() => {
    var target = targetRef.current;
    if (target !== null) {
      /**
       * End the hover gesture
       */
      var hoverEnd = function hoverEnd(e) {
        if (onHoverEnd != null) {
          onHoverEnd(e);
        }
        if (onHoverChange != null) {
          onHoverChange(false);
        }
        // Remove the listeners once finished.
        addMoveListener(target, null);
        addLeaveListener(target, null);
      };

      /**
       * Leave element
       */
      var leaveListener = function leaveListener(e) {
        var target = targetRef.current;
        if (target != null && getPointerType(e) !== 'touch') {
          if (contain) {
            dispatchCustomEvent(target, unlockEventType);
          }
          hoverEnd(e);
        }
      };

      /**
       * Move within element
       */
      var moveListener = function moveListener(e) {
        if (getPointerType(e) !== 'touch') {
          if (onHoverUpdate != null) {
            // Not all browsers have these properties
            if (e.x == null) {
              e.x = e.clientX;
            }
            if (e.y == null) {
              e.y = e.clientY;
            }
            onHoverUpdate(e);
          }
        }
      };

      /**
       * Start the hover gesture
       */
      var hoverStart = function hoverStart(e) {
        if (onHoverStart != null) {
          onHoverStart(e);
        }
        if (onHoverChange != null) {
          onHoverChange(true);
        }
        // Set the listeners needed for the rest of the hover gesture.
        if (onHoverUpdate != null) {
          addMoveListener(target, !disabled ? moveListener : null);
        }
        addLeaveListener(target, !disabled ? leaveListener : null);
      };

      /**
       * Enter element
       */
      var enterListener = function enterListener(e) {
        var target = targetRef.current;
        if (target != null && getPointerType(e) !== 'touch') {
          if (contain) {
            dispatchCustomEvent(target, lockEventType);
          }
          hoverStart(e);
          var lockListener = function lockListener(lockEvent) {
            if (lockEvent.target !== target) {
              hoverEnd(e);
            }
          };
          var unlockListener = function unlockListener(lockEvent) {
            if (lockEvent.target !== target) {
              hoverStart(e);
            }
          };
          addLockListener(target, !disabled ? lockListener : null);
          addUnlockListener(target, !disabled ? unlockListener : null);
        }
      };
      addEnterListener(target, !disabled ? enterListener : null);
    }
  }, [addEnterListener, addMoveListener, addLeaveListener, addLockListener, addUnlockListener, contain, disabled, onHoverStart, onHoverChange, onHoverUpdate, onHoverEnd, targetRef]);
}