import type Graphic from "../Graphic.js";
import type Collection from "../core/Collection.js";
import type GraphicsLayer from "../layers/GraphicsLayer.js";
import type View from "./View.js";
import type { EventedAccessor } from "../core/Evented.js";
import type { QueryProperties } from "../rest/support/Query.js";
import type { ObjectId } from "./types.js";
import type { LayerFeatureSet, LayerSelectionChange, SelectableLayer, SelectableLayerWithObjectIds, SelectionIdentifier, LayerSelection } from "./selection/types.js";

export interface SelectionManagerProperties extends Partial<Pick<SelectionManager, "highlightEnabled" | "highlightName" | "view">> {
  /**
   * A collection of selectable layers managed by the selection manager. Use `syncSources` to automatically populate this collection from the layers and tables in a [MapView](https://developers.arcgis.com/javascript/latest/references/core/views/MapView/) or [SceneView](https://developers.arcgis.com/javascript/latest/references/core/views/SceneView/).
   *
   * > [!CAUTION]
   * > When setting the sources property to an external Collection or array, the selection
   * > manager adds its contents to an internal Collection.
   * > Therefore, when the `SelectionManager` is destroyed, this internal `sources`
   * > Collection is always destroyed.
   *
   * @example
   * // Create a selection manager and set its view.
   * // Then, add a layer to its sources.
   * const selectionManager = new SelectionManager({
   *  view,
   *  sources: [featureLayer]
   * });
   * @example
   * // Later, if you want to add more layers, you can do so like this:
   * selectionManager.sources.add(anotherFeatureLayer);
   * // Or, if you want to replace the existing sources with a new set of layers:
   * selectionManager.sources = [differentFeatureLayer];
   * @see [syncSources](#syncSources)
   */
  sources?: Collection<SelectableLayer> | SelectableLayer[];
}

/** @since 5.0 */
export interface SelectionManagerEvents {
  /** @since 5.0 */
  "selection-change": {
      view: View | null | undefined;
      changes: LayerSelectionChange[];
  };
}

/**
 * A selection manager controls the selection of features in layers and tables within a [MapView](https://developers.arcgis.com/javascript/latest/references/core/views/MapView/) or [SceneView](https://developers.arcgis.com/javascript/latest/references/core/views/SceneView/) to help manage feature selection. It can be wired up to listen for edits made to selectable layers and have the selection update accordingly.
 *
 * @since 5.0
 * @beta
 * @example
 * // Create a selection manager and set its view.
 * // Then, add a layer to its sources.
 * const selectionManager = new SelectionManager({
 *  view,
 *  sources: [featureLayer]
 * });
 * // Select the features in the layer with specified Object IDs.
 * selectionManager.replace(featureLayer, [1, 2, 3]);
 */
export default class SelectionManager extends EventedAccessor {
  /**
   * @deprecated
   * Do not directly reference this property.
   * Use EventNames and EventTypes helpers from \@arcgis/core/Evented
   */
  "@eventTypes": SelectionManagerEvents;
  constructor(properties?: SelectionManagerProperties);
  /** The total number of selected features across all sources. */
  get count(): number;
  /** Returns `true` if at least one source has an active selection. */
  get hasSelection(): boolean;
  /**
   * Indicates whether to display a visual representation of the selection with a highlight.
   *
   * @default true
   */
  accessor highlightEnabled: boolean;
  /**
   * The [highlights name](https://developers.arcgis.com/javascript/latest/references/core/views/support/HighlightOptions/#name) to use when specifying a set of [highlight options](https://developers.arcgis.com/javascript/latest/references/core/views/support/HighlightOptions/).
   *
   * @default "default"
   * @see [MapView.highlights](https://developers.arcgis.com/javascript/latest/references/core/views/MapView/#highlights)
   * @see [HighlightOptions](https://developers.arcgis.com/javascript/latest/references/core/views/support/HighlightOptions/)
   */
  accessor highlightName: string;
  /** A read-only copy of the selection. To modify selections, use [add](#add), [replace](#replace), [remove](#remove), or [toggle](#toggle). */
  get selections(): LayerSelection[];
  /**
   * A collection of selectable layers managed by the selection manager. Use `syncSources` to automatically populate this collection from the layers and tables in a [MapView](https://developers.arcgis.com/javascript/latest/references/core/views/MapView/) or [SceneView](https://developers.arcgis.com/javascript/latest/references/core/views/SceneView/).
   *
   * > [!CAUTION]
   * > When setting the sources property to an external Collection or array, the selection
   * > manager adds its contents to an internal Collection.
   * > Therefore, when the `SelectionManager` is destroyed, this internal `sources`
   * > Collection is always destroyed.
   *
   * @example
   * // Create a selection manager and set its view.
   * // Then, add a layer to its sources.
   * const selectionManager = new SelectionManager({
   *  view,
   *  sources: [featureLayer]
   * });
   * @example
   * // Later, if you want to add more layers, you can do so like this:
   * selectionManager.sources.add(anotherFeatureLayer);
   * // Or, if you want to replace the existing sources with a new set of layers:
   * selectionManager.sources = [differentFeatureLayer];
   * @see [syncSources](#syncSources)
   */
  get sources(): Collection<SelectableLayer>;
  set sources(value: Collection<SelectableLayer> | SelectableLayer[]);
  /**
   * Indicates whether the selection manager is currently updating the view's visualization of selections.
   *
   * @default false
   */
  get updating(): boolean;
  /** A reference to the [MapView](https://developers.arcgis.com/javascript/latest/references/core/views/MapView/), or [SceneView](https://developers.arcgis.com/javascript/latest/references/core/views/SceneView/). This property must be set if wanting to highlight a corresponding feature within the map when a row is selected. In addition, setting the `view` is required if working with [layer views](https://developers.arcgis.com/javascript/latest/references/core/views/layers/LayerView/). */
  accessor view: View | null | undefined;
  /**
   * Adds features to the current selection. It does not replace the existing selection.
   *
   * @param layer - The selectable layer to which to add the selection. This must be a layer with graphics in the [sources](#sources).
   * @param selection - An array of features, ie. [Graphic[]](https://developers.arcgis.com/javascript/latest/references/core/Graphic/) to add to the current selection.
   */
  add(layer: GraphicsLayer, selection: Graphic[]): void;
  /**
   * Adds features to the current selection. It does not replace the existing selection.
   *
   * @param layer - The selectable layer to which to add the selection. This must be a layer with object IDs in the [sources](#sources).
   * @param selection - An array of features, ie. [ObjectId](https://developers.arcgis.com/javascript/latest/references/core/views/types/#ObjectId)[] to add to the current selection.
   */
  add(layer: SelectableLayerWithObjectIds, selection: ObjectId[] | Graphic[]): void;
  /**
   * Adds features to the current selection. It does not replace the existing selection.
   *
   * @param layer - The selectable layer to which to add the selection. This must be a layer in the [sources](#sources). It can be a layer with graphics or object IDs.
   * @param selection - An array of features, ie. [Graphic[]](https://developers.arcgis.com/javascript/latest/references/core/Graphic/) or [ObjectId](https://developers.arcgis.com/javascript/latest/references/core/views/types/#ObjectId)[] to add to the current selection.
   */
  add(layer: SelectableLayer, selection: SelectionIdentifier[]): void;
  /** Clears all selections from all layers. */
  clear(): void;
  /**
   * Queries the selected features for one or more layers. It uses the
   * current selection identifiers to fetch feature data from
   * the layer which may include attributes, geometry, etc. depending on the layer's capabilities and the supplied `queryParams`.
   *
   * @param includeLayers - Specifies the layer from which to fetch features. If not provided, all layers with active selections are queried.
   * @param queryParams - If supplied, it may include any supplemental parameters to thin out the feature results. The object IDs will also be part of the generated query.
   * @param queryTarget - If `"layer"`, applies all queries to the layer itself rather than the layer view. This can be used to bypass any client-side filtering that may be applied within the layer view. Note that not all layers support querying on the layer itself, so this option should be used with caution. If a layer does not support querying on the layer itself, the query will automatically be applied to the layer view instead.
   * @returns A promise that resolves to an array of [LayerFeatureSet](https://developers.arcgis.com/javascript/latest/references/core/views/selection/types/#LayerFeatureSet), which includes the layer and the resulting features for that layer.
   * @name getSelectedFeatures
   */
  getSelectedFeatures(includeLayers?: SelectableLayerWithObjectIds[], queryParams?: QueryProperties, queryTarget?: "layerView" | "layer"): Promise<LayerFeatureSet[]>;
  /**
   * Gets the active selection for the provided layer. If the layer is not part of the [sources](#sources) or has no active selection, this method returns `undefined`. Otherwise, it returns an array of selected features, which can be either [Graphic[]](https://developers.arcgis.com/javascript/latest/references/core/Graphic/) or [ObjectId](https://developers.arcgis.com/javascript/latest/references/core/views/types/#ObjectId)[] depending on the layer's capabilities. To retrieve the full graphic representations of selected features from a layer that supports only object ID selection, use the [getSelectedFeatures](#getSelectedFeatures) method. This method queries the layer using the selected object IDs and returns the corresponding feature graphics.
   *
   * @param target - The selectable layer that provides the selected features. This must be a layer with graphics in the [sources](#sources).
   * @returns Returns an array of [Graphic](https://developers.arcgis.com/javascript/latest/references/core/Graphic/)s representing the selected features.
   */
  getSelection(target: GraphicsLayer): Graphic[] | undefined;
  /**
   * @param target - The selectable layer that provides the selected features. This must be a layer with object IDs in the [sources](#sources).
   * @returns Returns an array of [ObjectId's](https://developers.arcgis.com/javascript/latest/references/core/views/types/#ObjectId) representing the selected features.
   */
  getSelection(target: SelectableLayerWithObjectIds): ObjectId[] | undefined;
  /**
   * @param target - The selectable layer that provides the selected features.This must be a layer in the [sources](#sources). It can be a layer with graphics or object IDs.
   * @returns Returns an array of selected features represented as either [Graphic[]](https://developers.arcgis.com/javascript/latest/references/core/Graphic/) or [ObjectId](https://developers.arcgis.com/javascript/latest/references/core/views/types/#ObjectId)[] dependent upon the layer's capabilities.
   */
  getSelection(target: SelectableLayer): SelectionIdentifier[] | undefined;
  /**
   * Removes the provided features from the current selection for the provided layer.
   *
   * @param layer - The selectable layer from which to remove the selection. This must be a layer with graphics in the [sources](#sources).
   * @param selection - An array of features, ie. [Graphic[]](https://developers.arcgis.com/javascript/latest/references/core/Graphic/) to remove from the current selection.
   */
  remove(layer: GraphicsLayer, selection: Graphic[]): void;
  /**
   * @param layer - The selectable layer from which to remove the selection. This must be a layer with object IDs in the [sources](#sources).
   * @param selection - An array of features, ie. [ObjectId](https://developers.arcgis.com/javascript/latest/references/core/views/types/#ObjectId)[] to remove from the current selection.
   */
  remove(layer: SelectableLayerWithObjectIds, selection: ObjectId[] | Graphic[]): void;
  /**
   * @param layer - The selectable layer from which to remove the selection. This must be a layer in the [sources](#sources). It can be a layer with graphics or object IDs.
   * @param selection - An array of features, ie. [Graphic[]](https://developers.arcgis.com/javascript/latest/references/core/Graphic/) or [ObjectId](https://developers.arcgis.com/javascript/latest/references/core/views/types/#ObjectId)[] to remove from the current selection.
   */
  remove(layer: SelectableLayer, selection: SelectionIdentifier[]): void;
  /**
   * Replaces the current selection for the provided layer with the provided features.
   *
   * @param layer - The selectable layer for which to replace the selection. This must be a layer with graphics in the [sources](#sources).
   * @param selection - An array of features, ie. [Graphic[]](https://developers.arcgis.com/javascript/latest/references/core/Graphic/) to set as the current selection.
   */
  replace(layer: GraphicsLayer, selection: Graphic[]): void;
  /**
   * @param layer - The selectable layer for which to replace the selection. This must be a layer with object IDs in the [sources](#sources).
   * @param selection - An array of features, ie. [ObjectId](https://developers.arcgis.com/javascript/latest/references/core/views/types/#ObjectId)[] to set as the current selection.
   */
  replace(layer: SelectableLayerWithObjectIds, selection: ObjectId[] | Graphic[]): void;
  /**
   * @param layer - The selectable layer for which to replace the selection. This must be a layer in the [sources](#sources). It can be a layer with graphics or object IDs.
   * @param selection - An array of features, ie. [Graphic[]](https://developers.arcgis.com/javascript/latest/references/core/Graphic/) or [ObjectId](https://developers.arcgis.com/javascript/latest/references/core/views/types/#ObjectId)[] to set as the current selection.
   */
  replace(layer: SelectableLayer, selection: SelectionIdentifier[]): void;
  /**
   * A convenience method to synchronize the [sources](#sources) with the layers and tables in the provided view. This is useful when layers or tables have been added or removed from the [View](https://developers.arcgis.com/javascript/latest/references/core/views/View/). This method is not applicable if [Map](https://developers.arcgis.com/javascript/latest/references/core/Map/) is not provided with the view.
   *
   * @see [sources](#sources)
   * @example
   * // Add a layer to the view's map after the selection manager has already been created
   * // and synced with the existing layers.
   * // Then, call syncSources to update the selection manager with the new layer.
   * const selectionManager = new SelectionManager({
   *   view: someView
   * });
   * someView.map.add(featureLayer);
   * selectionManager.syncSources();
   */
  syncSources(): void;
  /**
   * Toggles selection for the provided features within the provided layer's selection set.
   * If a given feature is part of the current set it will be removed, otherwise it will be added.
   * This method is designed to make it easy to toggle features in/out of the selected set in response to a query or UI event.
   *
   * @param layer - The selectable layer for which to toggle the selection. This must be a layer with graphics in the [sources](#sources).
   * @param selection - An array of features, ie. [Graphic[]](https://developers.arcgis.com/javascript/latest/references/core/Graphic/) to toggle within the current selection.
   */
  toggle(layer: GraphicsLayer, selection: Graphic[]): void;
  /**
   * @param layer - The selectable layer for which to toggle the selection. This must be a layer with object IDs in the [sources](#sources).
   * @param selection - An array of features, ie. [ObjectId](https://developers.arcgis.com/javascript/latest/references/core/views/types/#ObjectId)[] to toggle within the current selection.
   */
  toggle(layer: SelectableLayerWithObjectIds, selection: ObjectId[] | Graphic[]): void;
  /**
   * @param layer - The selectable layer for which to toggle the selection. This must be a layer in the [sources](#sources). It can be a layer with graphics or object IDs.
   * @param selection - An array of features, ie. [Graphic[]](https://developers.arcgis.com/javascript/latest/references/core/Graphic/) or [ObjectId](https://developers.arcgis.com/javascript/latest/references/core/views/types/#ObjectId)[] to toggle within the current selection.
   */
  toggle(layer: SelectableLayer, selection: SelectionIdentifier[]): void;
}