import { createAction, createListenerMiddleware } from '@reduxjs/toolkit';
import { selectActiveLabel, selectActiveTooltipCoordinate, selectActiveTooltipDataKey, selectActiveTooltipIndex, selectIsTooltipActive } from './selectors/tooltipSelectors';
import { createEventProxy } from '../util/createEventProxy';
export var externalEventAction = createAction('externalEvent');
export var externalEventsMiddleware = createListenerMiddleware();

/*
 * We need a Map keyed by event type because this middleware handles MULTIPLE different event types
 * (click, mouseenter, mouseleave, mousedown, mouseup, contextmenu, dblclick, touchstart, touchmove, touchend)
 * from the same DOM element. Different event types should NOT cancel each other's animation frames.
 * For example, a click event and a mousemove event can happen in quick succession and both should be processed.
 * This is different from mouseMoveMiddleware which only handles one event type and uses a single rafId.
 */
var rafIdMap = new Map();
var timeoutIdMap = new Map();
var latestEventMap = new Map();
externalEventsMiddleware.startListening({
  actionCreator: externalEventAction,
  effect: (action, listenerApi) => {
    var {
      handler,
      reactEvent
    } = action.payload;
    if (handler == null) {
      return;
    }
    var eventType = reactEvent.type;
    var eventProxy = createEventProxy(reactEvent);
    latestEventMap.set(eventType, {
      handler,
      reactEvent: eventProxy
    });

    // Cancel any pending execution for this event type
    var existingRafId = rafIdMap.get(eventType);
    if (existingRafId !== undefined) {
      cancelAnimationFrame(existingRafId);
      rafIdMap.delete(eventType);
    }
    var state = listenerApi.getState();
    var {
      throttleDelay,
      throttledEvents
    } = state.eventSettings;

    /*
     * reactEvent.type gives us the event type as a string, e.g., 'click', 'mousemove', etc.
     * which is the same as the names used in throttledEvents array
     * but that array is strictly typed as ReadonlyArray<keyof GlobalEventHandlersEventMap> | 'all' | undefined
     * so that we can have relevant autocomplete and type checking elsewhere.
     * This makes TypeScript panic because it refuses to call .includes() on ReadonlyArray<keyof GlobalEventHandlersEventMap>
     * with a string argument.
     * To satisfy TypeScript, we need to explicitly typecast throttledEvents here.
     */
    var eventListAsString = throttledEvents;

    // Check if this event type should be throttled
    // throttledEvents can be 'all' or an array of event names
    var isThrottled = eventListAsString === 'all' || (eventListAsString === null || eventListAsString === void 0 ? void 0 : eventListAsString.includes(eventType));
    var existingTimeoutId = timeoutIdMap.get(eventType);
    if (existingTimeoutId !== undefined && (typeof throttleDelay !== 'number' || !isThrottled)) {
      clearTimeout(existingTimeoutId);
      timeoutIdMap.delete(eventType);
    }
    var callback = () => {
      var latestAction = latestEventMap.get(eventType);
      try {
        if (!latestAction) {
          // This happens if the event was consumed by the leading edge and no new event came in
          return;
        }
        var {
          handler: latestHandler,
          reactEvent: latestEvent
        } = latestAction;
        var currentState = listenerApi.getState();
        var nextState = {
          activeCoordinate: selectActiveTooltipCoordinate(currentState),
          activeDataKey: selectActiveTooltipDataKey(currentState),
          activeIndex: selectActiveTooltipIndex(currentState),
          activeLabel: selectActiveLabel(currentState),
          activeTooltipIndex: selectActiveTooltipIndex(currentState),
          isTooltipActive: selectIsTooltipActive(currentState)
        };
        if (latestHandler) {
          latestHandler(nextState, latestEvent);
        }
      } finally {
        rafIdMap.delete(eventType);
        timeoutIdMap.delete(eventType);
        latestEventMap.delete(eventType);
      }
    };
    if (!isThrottled) {
      // Execute immediately
      callback();
      return;
    }
    if (throttleDelay === 'raf') {
      var rafId = requestAnimationFrame(callback);
      rafIdMap.set(eventType, rafId);
    } else if (typeof throttleDelay === 'number') {
      if (!timeoutIdMap.has(eventType)) {
        /*
         * Leading edge execution - execute immediately on the first event
         * and then start the cooldown period to throttle subsequent events.
         */
        callback();

        // Start cooldown
        var timeoutId = setTimeout(callback, throttleDelay);
        timeoutIdMap.set(eventType, timeoutId);
      }
    } else {
      // Should not happen based on type, but fallback to immediate
      callback();
    }
  }
});