/**
 * This object contains a helper method for generating a [dot density visualization](https://developers.arcgis.com/javascript/latest/references/core/renderers/DotDensityRenderer/).
 * The [createRenderer()](https://developers.arcgis.com/javascript/latest/references/core/smartMapping/renderers/dotDensity/#createRenderer) method uses the view's background to determine the most
 * appropriate dot color for each attribute. It also queries the layer for spatial statistics to determine
 * an appropriate [dot value](https://developers.arcgis.com/javascript/latest/references/core/renderers/DotDensityRenderer/#dotValue) for the
 * given scale. The starting dot value isn't necessarily what will work best for your data. Rather, it
 * is a suggestion that should give you a good starting point for authoring a dot density renderer.
 *
 * > [!WARNING]
 * >
 * > **Known Limitations**
 * >
 * > [DotDensityRenderer](https://developers.arcgis.com/javascript/latest/references/core/renderers/DotDensityRenderer/) is currently not supported in 3D [SceneViews](https://developers.arcgis.com/javascript/latest/references/core/views/SceneView/).
 * > Only layers with polygon geometries are supported.
 *
 * @since 4.12
 * @see [Sample - Generate a predominance visualization](https://developers.arcgis.com/javascript/latest/sample-code/visualization-sm-predominance/)
 * @see [ArcGIS Blog: Creating a predominance visualization with Arcade](https://www.esri.com/arcgis-blog/products/js-api-arcgis/mapping/creating-a-predominance-visualization-with-arcade/)
 * @see [ArcGIS Blog: Map Multiple Attributes at Once using Predominance](https://www.esri.com/arcgis-blog/products/arcgis-online/mapping/map-multiple-attributes-at-once-using-predominance/)
 * @see [Styles and data visualization](https://developers.arcgis.com/javascript/latest/visualization/)
 */
import type ImageryLayer from "../../layers/ImageryLayer.js";
import type PointCloudLayer from "../../layers/PointCloudLayer.js";
import type SceneLayer from "../../layers/SceneLayer.js";
import type StreamLayer from "../../layers/StreamLayer.js";
import type KnowledgeGraphSublayer from "../../layers/knowledgeGraph/KnowledgeGraphSublayer.js";
import type FeatureFilter from "../../layers/support/FeatureFilter.js";
import type DotDensityRenderer from "../../renderers/DotDensityRenderer.js";
import type MapView from "../../views/MapView.js";
import type { AbortOptions } from "../../core/promiseUtils.js";
import type { SupportedLayer } from "../types.js";
import type { Attribute } from "../statistics/types.js";
import type { DotDensityScheme, BasemapTheme } from "../symbology/types.js";

/**
 * Generates a [DotDensityRenderer](https://developers.arcgis.com/javascript/latest/references/core/renderers/DotDensityRenderer/) based on one or more complementary numeric fields
 * and/or Arcade expressions. This method will determine an appropriate [DotDensityRenderer.dotValue](https://developers.arcgis.com/javascript/latest/references/core/renderers/DotDensityRenderer/#dotValue)
 * for the data at the scale of the provided view.
 *
 * For example, suppose you have a layer of U.S. counties with fields containing the total sales of
 * various crops: wheat, soybeans, corn, cotton, and vegetables. If a feature has the following values for each field:
 *
 * Field Name | Count | Color
 * -----------|-------|------
 * Wheat | 140 | purple
 * Soybeans | 2000 | blue
 * Corn | 0 | yellow
 * Cotton | 300 | green
 * Vegetables | 120 | red
 *
 * This method will generate a renderer that may determine the `dotValue` should be `20`. The
 * feature with the data above will be rendered with a random placement of 6 purple dots, 100 blue dots,
 * no yellow dots, 60 green dots, and 5 red dots.
 *
 * The suggested value is calculated based
 * on a sampling of features. So executing this method multiple times using the same parameters may yield
 * varied results.
 *
 * Other options are provided for convenience for more involved custom visualization authoring
 * applications.
 *
 * @param parameters - Input parameters for generating a dot density visualization based on a set of complementary numeric field(s).
 * @returns Resolves to an instance of [RendererResult](https://developers.arcgis.com/javascript/latest/references/core/smartMapping/renderers/dotDensity/#RendererResult).
 * @example
 * const layer = new FeatureLayer({
 *   url: "https://services.arcgis.com/V6ZHFr6zdgNZuVG0/arcgis/rest/services/USA_County_Crops_2007/FeatureServer/0"
 * });
 *
 * // will create a visualization of predominant crop by U.S. county
 *
 * const params = {
 *   layer: layer,
 *   view: view,
 *   attributes: [{
 *     field: "M217_07",
 *     label: "Vegetables"
 *   }, {
 *     field: "M188_07",
 *     label: "Cotton"
 *   }, {
 *     field: "M172_07",
 *     label: "Wheat"
 *   }, {
 *     field: "M193_07",
 *     label: "Soybeans"
 *   }, {
 *     field: "M163_07",
 *     label: "Corn"
 *   }]
 * };
 *
 * // when the promise resolves, apply the renderer to the layer
 * dotDensityRendererCreator.createRenderer(params)
 *   .then(function(response){
 *     layer.renderer = response.renderer;
 *   });
 */
export function createRenderer(parameters: RendererParameters): Promise<RendererResult>;

export interface RendererParameters extends AbortOptions {
  /**
   * The **polygon** layer
   *   for which the visualization 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?: Exclude<SupportedLayer, ImageryLayer | KnowledgeGraphSublayer | PointCloudLayer | SceneLayer | StreamLayer> | null;
  /**
   * A set of complementary numeric fields/expressions used as the basis of the dot density visualization. For example,
   *   if creating an election map, you would indicate the names of each field representing the candidate or political party where
   *   total votes are stored.
   */
  attributes?: Attribute[] | null;
  /** The MapView instance in which the visualization will be rendered. */
  view?: MapView | null;
  /**
   * Indicates whether to vary the value of each dot by the view's scale. This will set
   *   the [DotDensityRenderer.referenceScale](https://developers.arcgis.com/javascript/latest/references/core/renderers/DotDensityRenderer/#referenceScale) of the output renderer.
   *
   * @default true
   */
  dotValueOptimizationEnabled?: boolean | null;
  /**
   * Indicates whether to enable color blending of different colored dots rendered at the same pixel.
   *   This is only visible in highly dense and highly diverse features.
   *
   * @default true
   */
  dotBlendingEnabled?: boolean | null;
  /**
   * Indicates whether the
   *   polygon outline width should vary based on view scale. When false, no outline will be used in the output renderer.
   *
   * @default false
   */
  outlineOptimizationEnabled?: boolean | null;
  /**
   * In authoring apps,
   *   the user may select a pre-defined dot density scheme. Pass the scheme object to this property to avoid getting one based on the view's background.
   */
  dotDensityScheme?: DotDensityScheme | null;
  /**
   * Provides options for modifying [Legend](https://developers.arcgis.com/javascript/latest/references/map-components/components/arcgis-legend/) properties describing
   *   the visualization.
   */
  legendOptions?: RendererParamsLegendOptions | 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;
  /**
   * 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;
}

export interface RendererParamsLegendOptions {
  /**
   * Indicates the unit represented by each dot in the legend. For example, in a population
   *   density map, you might set the value of `people` to this param. The output renderer would display `1 dot = 300 people` in the Legend.
   */
  unit?: string;
}

/**
 * The result object of the [createRenderer()](https://developers.arcgis.com/javascript/latest/references/core/smartMapping/renderers/dotDensity/#createRenderer) method. See the table
 * below for details of each property.
 */
export interface RendererResult {
  /**
   * The object representing
   *   the dot density visualization. Set this on a layer's `renderer` property to update its visualization.
   */
  renderer: DotDensityRenderer;
  /** The dot density scheme used by the renderer based on the view's background. */
  dotDensityScheme: DotDensityScheme;
  /** The ID of the basemap used to determine the optimal colors of the dots. */
  basemapId?: string | null;
  /** Indicates whether the average color of the input view's basemap is `light` or `dark`. */
  basemapTheme?: BasemapTheme | null;
}