/**
 * A module for importing types used in Search modules.
 *
 * @since 4.33
 */
import type Graphic from "../../Graphic.js";
import type Collection from "../../core/Collection.js";
import type EsriError from "../../core/Error.js";
import type Extent from "../../geometry/Extent.js";
import type Multipoint from "../../geometry/Multipoint.js";
import type Point from "../../geometry/Point.js";
import type Polygon from "../../geometry/Polygon.js";
import type Polyline from "../../geometry/Polyline.js";
import type SpatialReference from "../../geometry/SpatialReference.js";
import type CIMSymbol from "../../symbols/CIMSymbol.js";
import type LineSymbol3D from "../../symbols/LineSymbol3D.js";
import type PictureMarkerSymbol from "../../symbols/PictureMarkerSymbol.js";
import type PointSymbol3D from "../../symbols/PointSymbol3D.js";
import type PolygonSymbol3D from "../../symbols/PolygonSymbol3D.js";
import type SimpleFillSymbol from "../../symbols/SimpleFillSymbol.js";
import type SimpleLineSymbol from "../../symbols/SimpleLineSymbol.js";
import type SimpleMarkerSymbol from "../../symbols/SimpleMarkerSymbol.js";
import type TextSymbol from "../../symbols/TextSymbol.js";
import type WebStyleSymbol from "../../symbols/WebStyleSymbol.js";
import type LayerSearchSource from "./LayerSearchSource.js";
import type LocatorSearchSource from "./LocatorSearchSource.js";
import type { AbortOptions } from "../../core/promiseUtils.js";
import type { MapViewOrSceneView } from "../../views/MapViewOrSceneView.js";

/** The result object returned from a [Search.search()](https://developers.arcgis.com/javascript/latest/api-reference/esri-widgets-Search.html#search). */
export interface SearchResult {
  /**
   * The extent, or bounding box, of the returned feature. The value depends on
   * the data source, with higher quality data sources returning extents closer to the `feature` obtained from the search.
   */
  extent?: Extent | null;
  /** The resulting feature or location obtained from the search. */
  feature: Graphic;
  /**
   * The target of the result, which is a [Graphic](https://developers.arcgis.com/javascript/latest/api-reference/esri-Graphic.html) used
   * for either [MapView goTo()](https://developers.arcgis.com/javascript/latest/api-reference/esri-views-MapView.html#goTo) or [SceneView goTo()](https://developers.arcgis.com/javascript/latest/api-reference/esri-views-SceneView.html#goTo) navigation.
   */
  target: Graphic;
  /** The string name of the geocoded location. */
  name: string;
  /** The key related to the suggest result. */
  key?: string | number | null;
  /** The index. */
  sourceIndex?: number | null;
}

/** The result object returned from a [Search.suggest()](https://developers.arcgis.com/javascript/latest/api-reference/esri-widgets-Search.html#suggest). */
export interface SuggestResult {
  /** The location of the suggest result. */
  location?: Point;
  /** The string name of the suggested location to geocode. */
  text?: string | null;
  /** The key related to the suggest result. */
  key?: string | number | null;
  /** The index of the currently selected result. */
  sourceIndex?: number | null;
}

/** Base interface of common search result properties returned from the [Search.search()](https://developers.arcgis.com/javascript/latest/api-reference/esri-widgets-Search.html#search) and [Search.suggest()](https://developers.arcgis.com/javascript/latest/api-reference/esri-widgets-Search.html#suggest) methods. */
export interface BaseSearchResults<T> {
  /** The [source](https://developers.arcgis.com/javascript/latest/api-reference/esri-widgets-Search.html#sources) of the selected result. */
  source: SupportedSearchSource;
  /** The source index. */
  sourceIndex: number;
  /** The error. */
  error?: EsriError;
  /** An array of results. */
  results?: T[];
}

/** Base interface of common response properties returned from the [Search.search()](https://developers.arcgis.com/javascript/latest/api-reference/esri-widgets-Search.html#search) and [Search.suggest()](https://developers.arcgis.com/javascript/latest/api-reference/esri-widgets-Search.html#suggest) methods. */
export interface BaseSearchResponse<T> {
  /** The index of the source from which suggestions are obtained. This value is `-1` when all sources are selected. */
  activeSourceIndex: number;
  /** The searched expression */
  searchTerm: string;
  /** The number of results. */
  numResults: number;
  /** An array of errors. */
  errors: T[];
  /**
   * An array of objects representing the results
   * of search.
   */
  results: T[];
}

/** The array of results returned from the [Search.search()](https://developers.arcgis.com/javascript/latest/api-reference/esri-widgets-Search.html#search). */
export type SearchResults = BaseSearchResults<SearchResult>;

/** The array of results returned from the [Search.suggest()](https://developers.arcgis.com/javascript/latest/api-reference/esri-widgets-Search.html#suggest). */
export type SuggestResults = BaseSearchResults<SuggestResult>;

/** When resolved, returns this response after calling [Search.search()](https://developers.arcgis.com/javascript/latest/api-reference/esri-widgets-Search.html#search). */
export type SearchResponse = BaseSearchResponse<SearchResults>;

/** When resolved, returns this response after calling [Search.suggest()](https://developers.arcgis.com/javascript/latest/api-reference/esri-widgets-Search.html#suggest). */
export type SuggestResponse = BaseSearchResponse<SuggestResults>;

export type SearchItem = SuggestResult | string | Point | number[] | Graphic;

export type SupportedSearchSource = LocatorSearchSource | LayerSearchSource;

export interface SearchDefaultSymbols {
  /** A [SimpleMarkerSymbol](https://developers.arcgis.com/javascript/latest/api-reference/esri-symbols-SimpleMarkerSymbol.html), [PictureMarkerSymbol](https://developers.arcgis.com/javascript/latest/api-reference/esri-symbols-PictureMarkerSymbol.html), [PointSymbol3D](https://developers.arcgis.com/javascript/latest/api-reference/esri-symbols-PointSymbol3D.html), [TextSymbol](https://developers.arcgis.com/javascript/latest/api-reference/esri-symbols-TextSymbol.html), [CIMSymbol](https://developers.arcgis.com/javascript/latest/api-reference/esri-symbols-CIMSymbol.html), or [WebStyleSymbol](https://developers.arcgis.com/javascript/latest/api-reference/esri-symbols-WebStyleSymbol.html) used for representing the point geometry that is being drawn for the search result. [SimpleMarkerSymbol](https://developers.arcgis.com/javascript/latest/api-reference/esri-symbols-SimpleMarkerSymbol.html) may also be used to symbolize point features in a [SceneView](https://developers.arcgis.com/javascript/latest/api-reference/esri-views-SceneView.html). However, it is recommended you use [PointSymbol3D](https://developers.arcgis.com/javascript/latest/api-reference/esri-symbols-PointSymbol3D.html) instead. */
  point: SimpleMarkerSymbol | PictureMarkerSymbol | PointSymbol3D | TextSymbol | CIMSymbol | WebStyleSymbol;
  /** A [SimpleFillSymbol](https://developers.arcgis.com/javascript/latest/api-reference/esri-symbols-SimpleFillSymbol.html), [PolygonSymbol3D](https://developers.arcgis.com/javascript/latest/api-reference/esri-symbols-PolygonSymbol3D.html), or [CIMSymbol](https://developers.arcgis.com/javascript/latest/api-reference/esri-symbols-CIMSymbol.html) used for representing the polygon geometry that is being drawn for the search result. [SimpleFillSymbol](https://developers.arcgis.com/javascript/latest/api-reference/esri-symbols-SimpleFillSymbol.html) may also be used to symbolize polygon features in a [SceneView](https://developers.arcgis.com/javascript/latest/api-reference/esri-views-SceneView.html). However, it is recommended you use [PolygonSymbol3D](https://developers.arcgis.com/javascript/latest/api-reference/esri-symbols-PolygonSymbol3D.html) instead. */
  polygon: SimpleFillSymbol | PolygonSymbol3D | CIMSymbol;
  /** A [SimpleLineSymbol](https://developers.arcgis.com/javascript/latest/api-reference/esri-symbols-SimpleLineSymbol.html), [LineSymbol3D](https://developers.arcgis.com/javascript/latest/api-reference/esri-symbols-LineSymbol3D.html), or [CIMSymbol](https://developers.arcgis.com/javascript/latest/api-reference/esri-symbols-CIMSymbol.html) used for representing the polyline geometry that is being drawn for the search result. [SimpleLineSymbol](https://developers.arcgis.com/javascript/latest/api-reference/esri-symbols-SimpleLineSymbol.html) may also be used to symbolize polyline features in a [SceneView](https://developers.arcgis.com/javascript/latest/api-reference/esri-views-SceneView.html). However, it is recommended you use [LineSymbol3D](https://developers.arcgis.com/javascript/latest/api-reference/esri-symbols-LineSymbol3D.html) instead. */
  polyline: SimpleLineSymbol | LineSymbol3D | CIMSymbol;
}

/** @param options - The options object. */
export type SourcesHandler = (options: SourcesHandlerOptions) => Collection<SupportedSearchSource>;

export interface SourcesHandlerOptions {
  /** The collection of sources currently configured in the Search widget. */
  sources: Collection<SupportedSearchSource>;
  /** The collection of default sources for the Search widget. */
  defaultSources: Collection<SupportedSearchSource>;
}

export type SearchGeometry = Extent | Multipoint | Point | Polygon | Polyline;

export interface SearchFilter {
  /**
   * The filter geometry for suggests or search results.
   * [Extent](https://developers.arcgis.com/javascript/latest/api-reference/esri-geometry-Extent.html) is the only supported geometry when working with [locator](https://developers.arcgis.com/javascript/latest/api-reference/esri-widgets-Search-LocatorSearchSource.html) sources.
   * See [Find Address Candidates](https://developers.arcgis.com/rest/services-reference/find-address-candidates.htm) for additional information.
   */
  geometry?: SearchGeometry;
  /** The where clause specified for filtering suggests or search results. */
  where?: string;
}

export interface GetParameters {
  /** Indicates the view provided using the source. */
  view?: MapViewOrSceneView | null;
  /** Indicates the index of the search source. */
  sourceIndex?: number | null;
  /** Indicates the spatial reference defined by the source. */
  spatialReference?: SpatialReference;
}

export interface GetResultsParameters extends GetParameters {
  /** The key field used to find the result. */
  exactMatch?: boolean | null;
  /** The location value used by the Search. */
  location?: Point | null;
  /** Indicates the maximum number of search results to return. */
  maxResults?: number | null;
  /** Indicates the Suggest Result that triggered the search for a result. */
  suggestResult: SuggestResult;
}

/**
 * Function definition for the [SearchSource.getResults](https://developers.arcgis.com/javascript/latest/api-reference/esri-widgets-Search-SearchSource.html#getResults) property.
 *
 * @param params - An object that is passed as a parameter to get search results.
 * @param options - Additional options.
 * @returns When resolved, returns an object containing an array of [search results](https://developers.arcgis.com/javascript/latest/api-reference/esri-widgets-Search-types.html#SearchResult).
 */
export type GetResultsCallback = (params: GetResultsParameters, options?: AbortOptions) => Promise<SearchResult[] | null | undefined>;

/**
 * Function definition for the [SearchSource.getSuggestions](https://developers.arcgis.com/javascript/latest/api-reference/esri-widgets-Search-SearchSource.html#getSuggestions) property.
 *
 * @param params - An object that is passed as a parameter to get search suggestions.
 * @param options - Additional options.
 * @returns When resolved, returns an object containing an array of [suggest results](https://developers.arcgis.com/javascript/latest/api-reference/esri-widgets-Search-types.html#SuggestResult).
 */
export type GetSuggestionsCallback = (params: GetSuggestionsParameters, options?: AbortOptions) => Promise<SuggestResult[] | null | undefined>;

export interface GetSuggestionsParameters extends GetParameters {
  /** Indicates search term used to find a suggestion. */
  suggestTerm: string;
  /** Indicates the maximum number of suggestions to return for the widget's input. */
  maxSuggestions?: number | null;
}