/**
 * Copyright (c) Nicolas Gallagher.
 * 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.
 *
 * @flow
 */

import invariant from 'fbjs/lib/invariant';
import type { Task } from './TaskQueue';
import TaskQueue from './TaskQueue';
import type { EventSubscription } from '../../vendor/react-native/vendor/emitter/EventEmitter';
import EventEmitter from '../../vendor/react-native/vendor/emitter/EventEmitter';
import requestIdleCallback from '../../modules/requestIdleCallback';
const _emitter = new EventEmitter<{
  interactionComplete: [],
  interactionStart: [],
}>();
const InteractionManager = {
  Events: {
    interactionStart: 'interactionStart',
    interactionComplete: 'interactionComplete'
  },
  /**
   * Schedule a function to run after all interactions have completed.
   */
  runAfterInteractions(task: ?Task): {
    then: Function,
    done: Function,
    cancel: Function,
  } {
    const tasks: Array<Task> = [];
    const promise = new Promise(resolve => {
      _scheduleUpdate();
      if (task) {
        tasks.push(task);
      }
      tasks.push({
        run: resolve,
        name: 'resolve ' + (task && task.name || '?')
      });
      _taskQueue.enqueueTasks(tasks);
    });
    return {
      then: promise.then.bind(promise),
      done: promise.then.bind(promise),
      cancel: () => {
        _taskQueue.cancelTasks(tasks);
      }
    };
  },
  /**
   * Notify manager that an interaction has started.
   */
  createInteractionHandle(): number {
    _scheduleUpdate();
    const handle = ++_inc;
    _addInteractionSet.add(handle);
    return handle;
  },
  /**
   * Notify manager that an interaction has completed.
   */
  clearInteractionHandle(handle: number) {
    invariant(!!handle, 'Must provide a handle to clear.');
    _scheduleUpdate();
    _addInteractionSet.delete(handle);
    _deleteInteractionSet.add(handle);
  },
  addListener: (_emitter.addListener.bind(_emitter): EventSubscription),
  /**
   *
   * @param deadline
   */
  setDeadline(deadline: number) {
    _deadline = deadline;
  }
};
const _interactionSet = new Set();
const _addInteractionSet = new Set();
const _deleteInteractionSet = new Set();
const _taskQueue = new TaskQueue({
  onMoreTasks: _scheduleUpdate
});
let _nextUpdateHandle: TimeoutID | number = 0;
let _inc = 0;
let _deadline = -1;

/**
 * Schedule an asynchronous update to the interaction state.
 */
declare function _scheduleUpdate(): any;
/**
 * Notify listeners, process queue, etc
 */
declare function _processUpdate(): any;
export default InteractionManager;