import type ExpressionInfo from "./ExpressionInfo.js";
import type { JSONSupport } from "../../core/JSONSupport.js";
import type { ExpressionInfoProperties } from "./ExpressionInfo.js";

export interface AggregateFieldProperties extends Partial<Pick<AggregateField, "alias" | "isAutoGenerated" | "name" | "onStatisticField" | "statisticType">> {
  /**
   * An object containing an [Arcade](https://developers.arcgis.com/javascript/latest/arcade/) expression, which evaluates for each child feature represented
   * by the aggregate graphic.
   * All results of the expression will be aggregated using
   * the given [statisticType](https://developers.arcgis.com/javascript/latest/references/core/layers/support/AggregateField/#statisticType).
   * This expression must follow
   * the specification defined by the [Arcade Visualization Profile](https://developers.arcgis.com/javascript/latest/arcade/#visualization).
   * Expressions must return a string or a number and may access data values from the layer's feature
   * with the `$feature` profile variable.
   *
   * @since 4.25
   * @example
   * // will create an aggregate field for the Population field of the layer.
   * aggregateField.onStatisticExpression = new ExpressionInfo({
   *   title: "Population per square kilometer",
   *   returnType: "number",
   *   expression: "$feature.population / AreaGeodetic($feature, 'square-kilometers')"
   * });
   */
  onStatisticExpression?: ExpressionInfoProperties;
}

/**
 * Defines the aggregate fields used in a layer visualized with
 * [FeatureReductionBinning](https://developers.arcgis.com/javascript/latest/references/core/layers/support/FeatureReductionBinning/) or
 * [FeatureReductionCluster](https://developers.arcgis.com/javascript/latest/references/core/layers/support/FeatureReductionCluster/).
 * An aggregate field aggregates data from a layer's field using a statistic type
 * such as the average or sum.
 *
 * @since 4.24
 * @see [FeatureReductionBinning](https://developers.arcgis.com/javascript/latest/references/core/layers/support/FeatureReductionBinning/)
 * @see [FeatureReductionCluster](https://developers.arcgis.com/javascript/latest/references/core/layers/support/FeatureReductionCluster/)
 * @example
 * featureReduction.fields = [{
 *   name: "SUM_population",
 *   alias: "Total population",
 *   onStatisticField: "population",
 *   statisticType: "sum"
 * }, {
 *   name: "AVG_age",
 *   alias: "Average age",
 *   onStatisticField: "age",
 *   statisticType: "avg"
 * }];
 */
export default class AggregateField extends JSONSupport {
  constructor(properties?: AggregateFieldProperties);
  /**
   * The display name that describes the aggregate field in the [Legend](https://developers.arcgis.com/javascript/latest/references/map-components/components/arcgis-legend/),
   * [Popup](https://developers.arcgis.com/javascript/latest/references/map-components/components/arcgis-popup/), and
   * other UI elements.
   *
   * @example aggregateField.alias = "Total population";
   */
  accessor alias: string | null | undefined;
  /**
   * Indicates whether the field was created internally by the JS API's rendering engine for
   * default [FeatureReductionCluster](https://developers.arcgis.com/javascript/latest/references/core/layers/support/FeatureReductionCluster/) visualizations. You should avoid
   * setting or changing this value. If `true`, then all other properties of the AggregateField are read-only.
   *
   * @default false
   * @since 4.25
   */
  accessor isAutoGenerated: boolean;
  /**
   * The name of the aggregate field. This should describe the layer's field and aggregation
   * method used. For example, if creating a field that contains the total population for
   * a set of features with a population field, then you could name this field `total_population`
   * or `population_sum`.
   *
   * This field name must start with a letter, and may only contain alphanumeric characters and underscore.
   *
   * @example
   * // names the aggregate field that will display the sum of the population
   * // for all points representing cities in the bin
   * aggregateField.name = "SUM_population";
   */
  accessor name: string;
  /**
   * An object containing an [Arcade](https://developers.arcgis.com/javascript/latest/arcade/) expression, which evaluates for each child feature represented
   * by the aggregate graphic.
   * All results of the expression will be aggregated using
   * the given [statisticType](https://developers.arcgis.com/javascript/latest/references/core/layers/support/AggregateField/#statisticType).
   * This expression must follow
   * the specification defined by the [Arcade Visualization Profile](https://developers.arcgis.com/javascript/latest/arcade/#visualization).
   * Expressions must return a string or a number and may access data values from the layer's feature
   * with the `$feature` profile variable.
   *
   * @since 4.25
   * @example
   * // will create an aggregate field for the Population field of the layer.
   * aggregateField.onStatisticExpression = new ExpressionInfo({
   *   title: "Population per square kilometer",
   *   returnType: "number",
   *   expression: "$feature.population / AreaGeodetic($feature, 'square-kilometers')"
   * });
   */
  get onStatisticExpression(): ExpressionInfo;
  set onStatisticExpression(value: ExpressionInfoProperties);
  /**
   * The name of the [layer field](https://developers.arcgis.com/javascript/latest/references/core/layers/FeatureLayer/#fields) to summarize with the given [statisticType](https://developers.arcgis.com/javascript/latest/references/core/layers/support/AggregateField/#statisticType).
   *
   * @since 4.25
   * @example
   * // will create an aggregate field for the Population field of the layer.
   * aggregateField.onStatisticField = "Population";
   */
  accessor onStatisticField: string;
  /**
   * Defines the type of statistic used to aggregate data returned from [onStatisticField](https://developers.arcgis.com/javascript/latest/references/core/layers/support/AggregateField/#onStatisticField)
   * or [onStatisticExpression](https://developers.arcgis.com/javascript/latest/references/core/layers/support/AggregateField/#onStatisticExpression).
   *
   * **Possible Values**
   *
   * Value | Description |
   * ----- | ----------- |
   * `avg` | The average of values in the aggregate. Only available for fields and expressions that return numbers.
   * `count` | The total number of features in the aggregate. A field does not need to be specified in this case.
   * `max` | The maximum of all values in the aggregate. Only available for fields and expressions that return numbers.
   * `min` | The minimum of all values in the aggregate. Only available for fields and expressions that return numbers.
   * `mode` | The most common or predominant value in the aggregate. Available for fields and expressions that return numbers or strings.
   * `sum` | The sum of all values in the aggregate. Only available for fields and expressions that return numbers.
   *
   * @since 4.25
   * @example
   * // will calculate the sum of the field specified in onStatisticField for all features in the bin.
   * outStatistic.statisticType = "sum";
   */
  accessor statisticType: "avg" | "avg_angle" | "sum" | "mode" | "count" | "min" | "max";
  /**
   * Creates a deep clone of the AggregateField object.
   *
   * @returns A deep clone of the object that
   *   invoked this method.
   * @example
   * // Creates a deep clone of the AggregateField object
   * const sumPopulationField = layer.featureReduction.fields.find( field => field.name === "SUM_population" ).clone();
   */
  clone(): AggregateField;
}