/**
 * Convenience methods for getting field names used for feature layer
 * [labeling](https://developers.arcgis.com/javascript/latest/references/core/layers/FeatureLayer/#labelingInfo),
 * [elevation](https://developers.arcgis.com/javascript/latest/references/core/layers/FeatureLayer/#elevationInfo),
 * [editor tracking](https://developers.arcgis.com/javascript/latest/references/core/layers/FeatureLayer/#editFieldsInfo)
 * and time span.
 *
 * @since 4.11
 */
import type CSVLayer from "../CSVLayer.js";
import type FeatureLayer from "../FeatureLayer.js";
import type GeoJSONLayer from "../GeoJSONLayer.js";
import type OGCFeatureLayer from "../OGCFeatureLayer.js";
import type SceneLayer from "../SceneLayer.js";
import type StreamLayer from "../StreamLayer.js";
import type SubtypeGroupLayer from "../SubtypeGroupLayer.js";
import type Field from "./Field.js";
import type FieldsIndex from "./FieldsIndex.js";
import type { RendererUnion } from "../../renderers/types.js";

/**
 * Gets the appropriate display field name to label a feature.
 *
 * @param layer - An array of fields to determine the display field from.
 * @returns The name of the display field to use for labeling.
 * @since 4.15
 */
export function getDisplayFieldName(layer: FeatureLayer | CSVLayer | GeoJSONLayer | OGCFeatureLayer | SceneLayer | StreamLayer): string | null | undefined;

/**
 * Returns an array of field names used in the Arcade expression for calculating the z-values of features
 * in the given feature layer's [FeatureLayer.elevationInfo](https://developers.arcgis.com/javascript/latest/references/core/layers/FeatureLayer/#elevationInfo).
 *
 * @param layer - The featureLayer to extract fields required for calculating feature z-values.
 * @returns When resolved, returns an array of field names.
 */
export function getElevationFields(layer: FeatureLayer | null | undefined): Promise<string[]>;

/**
 * Returns an array of field names related to time.
 * It includes the fields from the [FeatureLayer.timeInfo](https://developers.arcgis.com/javascript/latest/references/core/layers/FeatureLayer/#timeInfo),
 * and the `trackIdField`.
 *
 * @param layer - The Feature Layer from which to extract time fields.
 * @returns When resolved, returns an array of time field names.
 */
export function getTimeFields(layer: FeatureLayer | null | undefined): Promise<string[]>;

/**
 * Returns an array of editor tracking field names for a given layer.
 * It includes the fields from the [FeatureLayer.editFieldsInfo](https://developers.arcgis.com/javascript/latest/references/core/layers/FeatureLayer/#editFieldsInfo).
 *
 * @param layer - The layer from which to extract editor tracking fields.
 * @returns An array of field names used for editor tracking.
 */
export function getFeatureEditFields(layer: FeatureLayer | SubtypeGroupLayer): string[];

/**
 * Returns an array of geometry field names for a given layer.
 *
 * @param layer - The layer to extract geometry fields from.
 * @returns An array of geometry field names.
 * @since 4.19
 */
export function getFeatureGeometryFields(layer: FeatureLayer | SubtypeGroupLayer): string[];

/**
 * Returns an array of field names used in the Arcade expression for labeling features
 * in the given feature layer's [FeatureLayer.labelingInfo](https://developers.arcgis.com/javascript/latest/references/core/layers/FeatureLayer/#labelingInfo).
 *
 * @param layer - The Feature Layer from which to extract label fields.
 * @returns When resolved, returns an array of field names used for labeling.
 */
export function getLabelingFields(layer: FeatureLayer | null | undefined): Promise<string[]>;

/** Value from a specified field. */
export type FieldValue = null | undefined | string | number;

/**
 * Returns an array of field names referenced in one or more [Arcade](https://developers.arcgis.com/javascript/latest/arcade/) expressions
 * to be set on the given layer in either the renderer, labels, or popup template.
 * This is useful for when you want to request the data for these fields prior to updating a renderer
 * for fast visual updates or when you want to execute a client-side query on that data prior to
 * setting the Arcade expressions on the layer.
 *
 * @param layer - The layer for which the Arcade `expressions` are authored. This layer must have a `fields` property.
 * @param expressions - An array of [Arcade](https://developers.arcgis.com/javascript/latest/arcade/) expressions to be set on the given `layer`.
 * @returns Returns an array of field names declared either by the `$feature.fieldName` or `$feature[fieldName]` syntax.
 * @since 4.15
 * @see [Arcade - expression language](https://developers.arcgis.com/javascript/latest/arcade/)
 * @example
 * const windDirectionExpression = `
 *   $feature["WIND_DIRECT"];
 *   $feature["WIND_SPEED"];
 *   var DEG = $feature.WIND_DIRECT;
 *   var SPEED = $feature.WIND_SPEED;
 *   var DIR = When( SPEED == 0, "",
 *     (DEG < 22.5 && DEG >= 0) || DEG > 337.5, "N",
 *     DEG >= 22.5 && DEG < 67.5, "NE",
 *     DEG >= 67.5 && DEG < 112.5, "E",
 *     DEG >= 112.5 && DEG < 157.5, "SE",
 *     DEG >= 157.5 && DEG < 202.5, "S",
 *     DEG >= 202.5 && DEG < 247.5, "SW",
 *     DEG >= 247.5 && DEG < 292.5, "W",
 *     DEG >= 292.5 && DEG < 337.5, "NW", "" );
 *   return SPEED + " mph " + DIR;
 * `;
 *
 * const labelExpressions = [
 *   "Round($feature.TEMP) + '° F';",
 *   "$feature.R_HUMIDITY + '% RH'",
 *   "$feature.STATION_NAME",
 *   windDirectionExpression
 * ];
 *
 * // Assume the layer has only requested the OBJECTID field
 * fieldUtils.getExpressionFields(layer, labelExpressions)
 *  .then(function(fieldNames){
 *
 *   // fieldNames = ["R_HUMIDITY", "STATION_NAME", "TEMP", "WIND_DIRECT", "WIND_SPEED"]
 *   layer.outFields = fieldNames;
 *
 *   // Do something else like a client-side query with those fields
 *  }).catch(function(error){
 *    console.error(error);
 *  });
 */
export function getExpressionFields(layer: FeatureLayer | CSVLayer | GeoJSONLayer | SceneLayer | StreamLayer, expressions: string[]): Promise<string[]>;

/**
 * Returns an array of field names used in the layer's [Renderer](https://developers.arcgis.com/javascript/latest/references/core/renderers/Renderer/).
 *
 * @param renderer - Layer's renderer to collect field names used in that renderer.
 * @param fieldsIndex - The field index of the layer. It can be used to make case-insensitive lookups for a field by name.
 * @returns When resolved, returns an array of field names required by the layer's renderer, sorted in ascending order.
 * @since 4.30
 * @example const rendererFields = fieldUtils.getRendererFields(layer.renderer, layer.fieldsIndex);
 */
export function getRendererFields(renderer: RendererUnion | null | undefined, fieldsIndex: FieldsIndex<Field>): Promise<string[]>;