/**
 * This object contains a helper method for generating data-driven visualizations with continuous
 * opacity based on data returned from a field value or expression in a [Layer](https://developers.arcgis.com/javascript/latest/references/core/layers/Layer/).
 *
 * The [createVisualVariable()](https://developers.arcgis.com/javascript/latest/references/core/smartMapping/renderers/opacity/#createVisualVariable) method
 * generates an [opacity visual variable](https://developers.arcgis.com/javascript/latest/references/core/renderers/visualVariables/OpacityVariable/)
 * with default alpha values that are optimally mapped to data values based on the statistics of the indicated field.
 *
 * > [!WARNING]
 * >
 * > **Known Limitations**
 * >
 * > [SceneLayers](https://developers.arcgis.com/javascript/latest/references/core/layers/SceneLayer/) must have the `supportsRenderer` and `supportsLayerQuery` capabilities enabled unless a predefined [statistics](https://developers.arcgis.com/javascript/latest/references/core/smartMapping/statistics/types/#SummaryStatisticsResult) object is provided to the `statistics` parameter of the method. To check a SceneLayer's capabilities, use the [SceneLayer.getFieldUsageInfo()](https://developers.arcgis.com/javascript/latest/references/core/layers/SceneLayer/#getFieldUsageInfo) method.
 * > You cannot generate renderers and visual variables using SQL expressions for client-side [FeatureLayers](https://developers.arcgis.com/javascript/latest/references/core/layers/FeatureLayer/)
 * > in a [SceneView](https://developers.arcgis.com/javascript/latest/references/core/views/SceneView/).
 *
 * @since 4.6
 * @see [Styles and data visualization](https://developers.arcgis.com/javascript/latest/visualization/)
 */
import type FeatureFilter from "../../layers/support/FeatureFilter.js";
import type AuthoringInfo from "../../renderers/support/AuthoringInfo.js";
import type OpacityVariable from "../../renderers/visualVariables/OpacityVariable.js";
import type { MapViewOrSceneView } from "../../views/MapViewOrSceneView.js";
import type { AbortOptions } from "../../core/promiseUtils.js";
import type { VisualVariableLegendOptions as IVisualVariableLegendOptions } from "../../renderers/types.js";
import type { SummaryStatisticsResult } from "../statistics/types.js";
import type { FeatureLikeLayerOrAdapter } from "../support/adapters/types.js";

/**
 * This method generates an opacity visual variable
 * with default alpha values optimally mapped to data values based on the statistics
 * queried for the indicated field or expression.
 *
 * There are several ways this method may be called. The most common case is by
 * providing a `layer` and a `field`. This is the scenario where
 * the statistics of the data aren't well known and the user doesn't know the which
 * alpha values to map to data values. You can optionally use a `valueExpression` instead of a field to visualize
 * features based on a numeric value returned from a script executed at runtime.
 *
 * The other options are provided for convenience for more involved custom visualization authoring
 * applications. For example, if you already generated statistics in another operation, you
 * can pass the stats in the `statistics` parameter to avoid making an extra call to the server.
 *
 * @param parameters - Input parameters for generating an opacity visual variable based on data
 *   returned from a given field or expression.
 * @returns Resolves to an instance of
 *   [VisualVariableResult](https://developers.arcgis.com/javascript/latest/references/core/smartMapping/renderers/opacity/#VisualVariableResult).
 * @example
 * let layer = new FeatureLayer({
 *   url: "https://services.arcgis.com/V6ZHFr6zdgNZuVG0/arcgis/rest/services/counties_politics_poverty/FeatureServer/0"
 * });
 *
 * // visualization based on field and normalization field
 * let parameters = {
 *   layer: layer,
 *   field: "POP_POVERTY",
 *   normalizationField: "TOTPOP_CY"
 * };
 *
 * // when the promise resolves, apply the visual variable to the renderer
 * opacityVariableCreator.createVisualVariable(parameters)
 *   .then(function(response){
 *     let renderer = layer.renderer.clone();
 *     renderer.visualVariables = [ response.visualVariable ];
 *     layer.renderer = renderer;
 *   });
 * @example
 * let layer = new FeatureLayer({
 *   url: "https://services.arcgis.com/V6ZHFr6zdgNZuVG0/arcgis/rest/services/counties_politics_poverty/FeatureServer/0"
 * });
 *
 * // visualization based off Arcade expression
 * let parameters = {
 *   layer: layer,
 *   valueExpression: "($feature.POP_POVERTY / $feature.TOTPOP_CY) * 100",
 *   view: view,
 *   valueExpressionTitle: "% of people living in poverty"
 * };
 *
 * // when the promise resolves, apply the visual variable to the renderer
 * opacityVariableCreator.createVisualVariable(parameters)
 *   .then(function(response){
 *     let renderer = layer.renderer.clone();
 *     renderer.visualVariables = [ response.visualVariable ];
 *     layer.renderer = renderer;
 *   });
 */
export function createVisualVariable(parameters: VisualVariableParameters): Promise<VisualVariableResult>;

export interface VisualVariableParameters extends AbortOptions {
  /**
   * The layer for which the visual variable
   *   is generated. When a client-side layer type is provided, attribute and spatial statistics are calculated
   * only from features in the view's extent. When a server-side layer type is provided, the statistics
   * are calculated from the entire layer, unless a `valueExpression` is provided.
   */
  layer?: FeatureLikeLayerOrAdapter | null;
  /**
   * The name of the field whose data will be queried for statistics and used for
   *   the basis of the data-driven visualization.
   *   This property is ignored if a `valueExpression` is used.
   */
  field?: string | null;
  /**
   * The name of the field to normalize the values of the given
   *   `field`. Providing a normalization field helps minimize some visualization errors and standardizes the data
   *   so all features are visualized with minimal bias due to area differences or count variation. This option is
   *   commonly used when visualizing densities.
   */
  normalizationField?: string | null;
  /**
   * An [Arcade](https://developers.arcgis.com/javascript/latest/arcade/) expression following
   * the specification defined by the [Arcade Visualization Profile](https://developers.arcgis.com/javascript/latest/arcade/#visualization).
   * Expressions may reference field values using the `$feature` profile variable and must return
   * a number. This property overrides the `field` property and therefore is used instead of an input `field` value.
   * The `view` parameter is required if specifying a `valueExpression`. When using a `valueExpression`, client-side
   * statistics are calculated based on the features in the view's extent. To generate statistics for the entire layer,
   * set an equivalent `sqlExpression`.
   */
  valueExpression?: string | null;
  /**
   * Text describing the value returned from the `valueExpression`.
   *   This is used by the [Legend](https://developers.arcgis.com/javascript/latest/references/map-components/components/arcgis-legend/).
   */
  valueExpressionTitle?: string | null;
  /**
   * A SQL expression evaluating to a number. When provided, statistics are
   *   queried from the server for the entire layer. Only use this parameter when generating a renderer based on
   *   an equivalent `valueExpression`. This parameter is ignored for client-side layer types.
   */
  sqlExpression?: string | null;
  /**
   * A SQL where clause used to filter features for the statistics query. For example,
   *   this is useful in situations where you want to avoid dividing by zero as is the case with creating a predominance
   *   visualization.
   */
  sqlWhere?: string | null;
  /**
   * When defined, only features included in the filter
   *   are considered in the attribute and spatial statistics calculations when determining the final renderer.
   *   This is useful when a lot of variation exists in the data
   *   that could result in undesired data ranges. A common use case would be to set a filter that only
   *   includes features in the current extent of the view where the data is most likely to be viewed. Currently, only
   *   geometry filters with an `intersects` spatial relationship are supported. All other filter types (including `where`) are ignored.
   *
   * @since 4.31
   */
  filter?: FeatureFilter | null;
  /**
   * Provides options for setting a title to a field when an expression is provided
   *   instead of a field name. This title will represent the field in the [Legend](https://developers.arcgis.com/javascript/latest/references/map-components/components/arcgis-legend/).
   */
  legendOptions?: IVisualVariableLegendOptions | null;
  /**
   * A statistics object generated from the [summaryStatistics](https://developers.arcgis.com/javascript/latest/references/core/smartMapping/statistics/summaryStatistics/) function.
   *   If statistics for the field have already been generated, then pass the object here to avoid making a second statistics
   *   query to the server.
   */
  statistics?: SummaryStatisticsResult | null;
  /**
   * A custom minimum value set by the user. Use this in conjunction with `maxValue` to
   *   generate statistics between lower and upper bounds. This will be the lowest stop in the returned visual variable.
   */
  minValue?: number | null;
  /**
   * A custom maximum value set by the user. Use this in conjunction with `minValue` to
   *   generate statistics between lower and upper bounds. This will be the uppermost stop in the returned visual variable.
   */
  maxValue?: number | null;
  /**
   * Indicates whether the generated renderer is for a binning or clustering visualization.
   *   If `true`, then the input field(s) in this method should refer to [aggregate fields](https://developers.arcgis.com/javascript/latest/references/core/layers/support/AggregateField/) defined in the `featureReduction` property of the layer.
   */
  forBinning?: boolean | null;
  /**
   * A [SceneView](https://developers.arcgis.com/javascript/latest/references/core/views/SceneView/) or [MapView](https://developers.arcgis.com/javascript/latest/references/core/views/MapView/)
   *   instance is required when a `valueExpression` is specified.
   */
  view?: MapViewOrSceneView | null;
}

/**
 * The result object of the [createVisualVariable()](https://developers.arcgis.com/javascript/latest/references/core/smartMapping/renderers/opacity/#createVisualVariable) method. See the table
 * below for details of each property.
 */
export interface VisualVariableResult {
  /**
   * An opacity visual
   *   variable configured based on the statistics of the data.
   */
  visualVariable: OpacityVariable;
  /**
   * Indicates whether default values are used in the absence of sufficient
   *   data and/or statistics from the layer. Default values are typically used when all features have the same field
   *   value or no value at all.
   */
  defaultValuesUsed: boolean;
  /** Basic statistics returned from a query to the service for the given field or expression. */
  statistics: SummaryStatisticsResult;
  /**
   * Authoring information related to the creation of the visual variable.
   *   This includes information related to UI inputs from sliders and selected themes.
   */
  authoringInfo: AuthoringInfo;
}