import type Collection from "./Collection.js";

/**
 * This class helps manage a group of handles.
 *
 * @since 4.7
 */
export default class Handles<T = string, H extends ResourceHandle = ResourceHandle> {
  constructor();
  /**
   * Adds a group of handles.
   *
   * @param handles - An array or collection handles to group.
   * @param groupKey - Key identifying the group to which the handles should be added. All the handles in the group
   *    can later be removed with [remove()](https://developers.arcgis.com/javascript/latest/api-reference/esri-core-Handles.html#remove). If no
   *    key is provided the handles are added to a default group.
   * @example
   * let handles = new Handles();
   *
   * handles.add(handle); // added to the default group
   * handles.add([handle1, handle2]); // added to the default group
   *
   * handles.add(handle, "handle-group");
   * handles.add([handle1, handle2], "other-handle-group");
   * @example
   * let handles = new Handles();
   *
   * handles.add(reactiveUtils.when(
   *   () => !view.updating,
   *   () => {
   *     wkidSelect.disabled = false;
   *   },
   *   { once: true }
   * ));
   */
  add(handles: (H | null | undefined) | (H | null | undefined)[] | Collection<H | null | undefined>, groupKey?: T): this;
  /**
   * Destroys the object, removing all the handles.
   *
   * @example
   * let handles = new Handles();
   *
   * handles.add(reactiveUtils.when(
   *   () => !view.updating,
   *   () => {
   *     wkidSelect.disabled = false;
   *   },
   *   { once: true }
   * ));
   *
   * handles.destroy();
   */
  destroy(): void;
  /**
   * Returns true if a group exists for the provided group key, false otherwise.
   *
   * @param groupKey - group handle key
   */
  has(groupKey?: T): boolean;
  /**
   * Removes a group of handles.
   *
   * @param groupKey - A group key or an array or collection of group keys to remove.
   * @example
   * let handles = new Handles();
   *
   * handles.remove(); // removes handles from default group
   *
   * handles.remove("handle-group");
   * handles.remove("other-handle-group");
   */
  remove(groupKey?: T | T[] | Collection<T>): this;
  /** Removes all handles. */
  removeAll(): this;
}

/**
 * Represents a watch or event handler which can be removed.
 *
 * @example
 * let handle = reactiveUtils.watch(() => map.basemap, (newVal) => {
 *   // Each time the value of map.basemap changes, it is logged in the console
 *   console.log("new basemap: ", newVal);
 * });
 *
 * // When remove() is called on the watch handle, the map no longer watches for changes to basemap
 * handle.remove();
 */
export interface ResourceHandle {
  /** Removes the handle. */
  remove(): void;
}