import type Color from "../Color.js";
import type Point from "../geometry/Point.js";
import type Polygon from "../geometry/Polygon.js";
import type Polyline from "../geometry/Polyline.js";
import type Layer from "../layers/Layer.js";
import type Sublayer from "../layers/support/Sublayer.js";
import type LayerView from "../views/layers/LayerView.js";
import type { RelationshipFocus } from "../renderers/support/types.js";
import type { SymbolUnion } from "../symbols/types.js";
type LegendMessages = Record<string, unknown>;

/** The z axis orientation. */
export interface Axes {
  /** z axis orientation. */
  z?: number;
}

/** Describes a point in terms of a location, a [Point](https://developers.arcgis.com/javascript/latest/api-reference/esri-geometry-Point.html), and a coordinate, a string. */
export interface Position {
  /** A string representing the location. */
  coordinate?: string | null;
  /** A point geometry representing the location described by the conversion. */
  location?: Point | null;
}

export type Mode = "live" | "capture";

/**
 * This object describes how a Format should be projected and formatted for display.  Used to define
 * custom Formats that require custom conversion and/or projection logic.
 */
export interface ConversionInfo {
  /** A function that takes a point and returns a [Position](https://developers.arcgis.com/javascript/latest/api-reference/esri-widgets-types.html#Position). */
  convert?: ConvertFunction;
  /** A function that takes a string and returns a Point. */
  reverseConvert?: ReverseConvertFunction;
}

/**
 * A user-provided function that converts a [Point](https://developers.arcgis.com/javascript/latest/api-reference/esri-geometry-Point.html) into a
 * [Position](https://developers.arcgis.com/javascript/latest/api-reference/esri-widgets-types.html#Position). This function may
 * be necessary to provide as part of [ConversionInfo](https://developers.arcgis.com/javascript/latest/api-reference/esri-widgets-types.html#ConversionInfo)
 * when creating a custom [Format](https://developers.arcgis.com/javascript/latest/api-reference/esri-widgets-CoordinateConversion-support-Format.html).
 *
 * @param point - A point to be converted.
 * @returns The returned position.
 */
export type ConvertFunction = (point: Point) => Position;

/**
 * A user-provided function that converts a coordinate string into a [Point](https://developers.arcgis.com/javascript/latest/api-reference/esri-geometry-Point.html).
 * This function may be necessary to provide as part of [ConversionInfo](https://developers.arcgis.com/javascript/latest/api-reference/esri-widgets-types.html#ConversionInfo)
 * when creating a custom [Format](https://developers.arcgis.com/javascript/latest/api-reference/esri-widgets-CoordinateConversion-support-Format.html).
 *
 * @param coordinate - The string to be reversed.
 * @returns The returned point
 */
export type ReverseConvertFunction = (coordinate: string) => Point;

/**
 * A coordinate segment represents one piece of a coordinate string.
 *
 * > [!WARNING]
 * >
 * > A MGRS coordinate, for example `30UVG898998`, is described by four segments:
 * > 1. Alias `Z`, the gridzone: `30U`
 * > 2. Alias `S`, the 100,000 meter square designator: `VG`
 * > 3. Alias `X`, the easting (x coordinate with respect to the 10,000 meter square): `898`
 * > 4. Alias `Y`, the northing (y coordinate with respect to the 10,000 meter square): `998`
 */
export interface CoordinateSegment {
  /** A string that provides the name for this segment of a coordinate string. */
  alias: string;
  /** A string that describes the role of this segment. */
  description: string;
  /** A regular expression that should extract this segment from the complete coordinate. */
  searchPattern: RegExp;
}

/**
 * An object that defines a layer, optional sublayer IDs, and a custom title for legend display.
 * Use this to specify which layers and sublayers appear in the legend and how they are labeled with
 * [layerInfos](https://developers.arcgis.com/javascript/latest/api-reference/esri-widgets-Legend-LegendViewModel.html).
 */
export interface LayerInfo {
  /** A layer to display in the legend. */
  layer: Layer | Sublayer;
  /**
   * The IDs of the sublayers for which to display legend information.
   * Only applicable if the `layer` is a [MapImageLayer](https://developers.arcgis.com/javascript/latest/api-reference/esri-layers-MapImageLayer.html), [SubtypeGroupLayer](https://developers.arcgis.com/javascript/latest/api-reference/esri-layers-SubtypeGroupLayer.html)
   * or [WMSLayer](https://developers.arcgis.com/javascript/latest/api-reference/esri-layers-WMSLayer.html).
   */
  sublayerIds?: number[];
  /**
   * Specifies a title for the layer to display above its symbols and descriptions.
   * If no title is specified the service name is used.
   */
  title: string;
}

/** Properties defining the scheme of each of the supported [legendElement](https://developers.arcgis.com/javascript/latest/api-reference/esri-widgets-Legend-support-ActiveLayerInfo.html#legendElements). */
export type LegendElement = SymbolTableElement | ColorRampElement | StretchRampElement | OpacityRampElement | SizeRampElement | HeatmapRampElement | RelationshipRampElement | UnivariateColorSizeRampElement | PieChartRampElement;

/** Properties defining the scheme of each SymbolTableElementType. */
export type SymbolTableElementType = ImageSymbolTableElementInfo | SymbolTableElementInfo | LegendElement;

/**
 * Describes the schema of the SymbolTableElement used as a [legendElement](https://developers.arcgis.com/javascript/latest/api-reference/esri-widgets-Legend-support-ActiveLayerInfo.html#legendElements). This
 * legend element is used for [UniqueValueRenderer](https://developers.arcgis.com/javascript/latest/api-reference/esri-renderers-UniqueValueRenderer.html) and
 * [ClassBreaksRenderer](https://developers.arcgis.com/javascript/latest/api-reference/esri-renderers-ClassBreaksRenderer.html). See the table below for more details of the properties in this object.
 */
export interface SymbolTableElement {
  /**
   * An
   *   array of each symbol/category/break rendered for the symbol table. For example, this may be individual
   *   breaks for a ClassBreaksRenderer, or unique values for a UniqueValueRenderer.
   */
  infos: SymbolTableElementType[];
  /**
   * Only used for renderers set to ImageryLayers. Indicates the type of
   *   renderer set on the layer (e.g. `stretched` or `Unique Values`).
   */
  legendType?: string | null;
  /** The title of the renderer as displayed in the legend. */
  title?: RendererTitle | DotDensityTitle | string | null;
  /** The type of this element is always `symbol-table`. */
  type: "symbol-table";
}

/** Properties defining the scheme of the SymbolTableElementInfo. */
export interface SymbolTableElementInfo {
  /**
   * The
   *   title of the renderer as displayed in the Legend.
   */
  label?: RampTitle | string | null;
  /** A preview of the symbol element as displayed in the legend. */
  preview?: HTMLElement | null;
  /** The aria-label for the preview element. */
  previewAriaLabel?: RendererTitle | DotDensityTitle | string | null;
  /** The size of the symbol in points. */
  size?: number | null;
  /** The symbol for the corresponding `value` in the legend. */
  symbol: SymbolUnion;
  /** The value corresponding with the given `symbol` in the legend. */
  value?: any;
}

/**
 * Properties defining the scheme of each of the ImageSymbolTableElementInfo. This applies only to
 * ImageryLayer renderers.
 */
export interface ImageSymbolTableElementInfo {
  /** The height of the image in pixels. */
  height?: number | null;
  /** The label of the category corresponding to the given image. */
  label?: StretchMultibandTitle | string | null;
  /** The opacity of the image (`0` to `1`). */
  opacity?: number | null;
  /** The aria-label for the preview element. */
  previewAriaLabel?: RendererTitle | DotDensityTitle | string | null;
  /** The data URI of the image representing a colored pixel in the renderer. */
  src: string;
  /** The width of the image in pixels. */
  width?: number | null;
}

/**
 * Describes the schema of the ColorRampElement used as a [legendElement](https://developers.arcgis.com/javascript/latest/api-reference/esri-widgets-Legend-support-ActiveLayerInfo.html#legendElements).
 * See the table below for more details of the properties in this object.
 */
export interface ColorRampElement {
  /**
   * The
   *   individual color stops rendered in the legend that correspond to the color visual variable in the renderer.
   */
  infos: ColorRampStop[];
  /** A preview of the element as displayed in the legend. */
  preview?: HTMLElement | null;
  /** The title of the color ramp as displayed in the legend. */
  title?: RampTitle | string | null;
  /** The type of this element is always `color-ramp`. */
  type: "color-ramp";
}

/**
 * Describes the schema of the StretchRampElement used as a [legendElement](https://developers.arcgis.com/javascript/latest/api-reference/esri-widgets-Legend-support-ActiveLayerInfo.html#legendElements).
 * See the table below for more details of the properties in this object.
 */
export interface StretchRampElement {
  /**
   * The
   *   individual color stops rendered in the legend that correspond to the color visual variable in the renderer.
   */
  infos: ColorRampStop[];
  /** A preview of the element as displayed in the legend. */
  preview?: HTMLElement | null;
  /** The title of the color ramp as displayed in the legend. */
  title?: RampTitle | string | null;
  /** The type of this element is always `stretch-ramp`. */
  type: "stretch-ramp";
}

/**
 * Describes the schema of the OpacityRampElement used as a [legendElement](https://developers.arcgis.com/javascript/latest/api-reference/esri-widgets-Legend-support-ActiveLayerInfo.html#legendElements).
 * See the table below for more details of the properties in this object.
 */
export interface OpacityRampElement {
  /**
   * The
   *   individual opacity stops rendered in the legend that correspond to the opacity visual variable in the renderer.
   */
  infos: OpacityRampStop[];
  /** A preview of the element as displayed in the legend. */
  preview?: HTMLElement | null;
  /** The title of the opacity ramp as displayed in the legend. */
  title?: RampTitle | string | null;
  /** The type of this element is always `opacity-ramp`. */
  type: "opacity-ramp";
}

/**
 * Describes the schema of the SizeRampElement used as a [legendElement](https://developers.arcgis.com/javascript/latest/api-reference/esri-widgets-Legend-support-ActiveLayerInfo.html#legendElements).
 * See the table below for more details of the properties in this object.
 */
export interface SizeRampElement {
  /**
   * The
   *   individual size stops rendered in the legend that correspond to the size visual variable in the renderer.
   */
  infos: SizeRampStop[];
  /** The theme of this element. */
  theme?: "spike" | null;
  /** The title of the size ramp as displayed in the legend. */
  title?: ClusterTitle | RampTitle | string | null;
  /** The type of this element is always `size-ramp`. */
  type: "size-ramp";
}

/**
 * Describes the schema of the HeatmapRampElement used as a [legendElement](https://developers.arcgis.com/javascript/latest/api-reference/esri-widgets-Legend-support-ActiveLayerInfo.html#legendElements).
 * See the table below for more details of the properties in this object.
 */
export interface HeatmapRampElement {
  /**
   * The
   *   individual color stops rendered in the legend that correspond to the heatmap colorStops in the renderer.
   */
  infos: HeatmapRampStop[];
  /** A preview of the element as displayed in the legend. */
  preview?: HTMLElement | null;
  /** The title of the heatmap ramp as displayed in the legend. */
  title?: RendererTitle | string | null;
  /** The type of this element is always `heatmap-ramp`. */
  type: "heatmap-ramp";
}

/**
 * Describes the schema of the RelationshipRampElement used as a [legendElement](https://developers.arcgis.com/javascript/latest/api-reference/esri-widgets-Legend-support-ActiveLayerInfo.html#legendElements).
 * See the table below for more details of the properties in this object.
 */
export interface RelationshipRampElement {
  /** A 2-dimensional array of colors as displayed in the legend grid. */
  colors: Color[][];
  /** Determines the orientation of the Legend. Values can be `HH`, `HL`, `LH`, `LL`. */
  focus: RelationshipFocus;
  /** Info objects associated with the relationship renderer. */
  infos?: any[] | null;
  /**
   * The labels for
   *   each corner of the legend.
   */
  labels: RelationshipLabels;
  /**
   * The number of classes for each field comprising the renderer. Can either
   *   be 2, 3, or 4.
   */
  numClasses: number;
  /**
   * The rotation of the legend in degrees (0-360). `0` degrees displays the legend
   *   as a square with the `LL` cell in the bottom left corner of the legend and the `HH` cell in the top right corner.
   */
  rotation: number;
  /** The title of the renderer as displayed in the legend. */
  title?: string | null;
  /** The type of this element is always `relationship-ramp`. */
  type: "relationship-ramp";
}

/**
 * Describes the schema of the UnivariateColorSizeRampElement used as a [legendElement](https://developers.arcgis.com/javascript/latest/api-reference/esri-widgets-Legend-support-ActiveLayerInfo.html#legendElements).
 * See the table below for more details of the properties in this object.
 */
export interface UnivariateColorSizeRampElement {
  /**
   * The
   *   individual color stops rendered in the legend that correspond to the color visual variable in the renderer.
   */
  infos: (SizeRampElement | ColorRampElement)[];
  /** The title of the color ramp as displayed in the legend. */
  title?: ClusterTitle | RampTitle | string | null;
  /** The type of this element is `univariate-above-and-below-ramp` or `univariate-color-size-ramp`. */
  type: "univariate-above-and-below-ramp" | "univariate-color-size-ramp";
}

/**
 * Describes the schema of the UnivariateColorSizeRampElement used as a [legendElement](https://developers.arcgis.com/javascript/latest/api-reference/esri-widgets-Legend-support-ActiveLayerInfo.html#legendElements).
 * See the table below for more details of the properties in this object.
 */
export interface PieChartRampElement {
  /**
   * The
   *   individual color stops rendered in the legend that correspond to the color visual variable in the renderer.
   */
  infos: SymbolTableElementInfo[];
  /** A preview of the element as displayed in the legend. */
  preview?: HTMLElement | null;
  /** The title of the color ramp as displayed in the legend. */
  title?: RendererTitle | string | null;
  /** The type of this element is always `pie-chart-ramp`. */
  type: "pie-chart-ramp";
}

/** Describes the schema of the RendererTitle element. */
export interface RendererTitle {
  /**
   * The field name used in the renderer. This is used in the
   *   generated title of the renderer in the legend.
   */
  field?: string | null;
  /**
   * Indicates if a percentage is used in the normalization of the
   *   renderer. This is used to create a more readable legend for that scenario.
   */
  normByPct?: boolean | null;
  /**
   * If a normalization field is provided to the renderer, this field
   *   is also used in the generated title for the renderer in the legend.
   */
  normField?: string | null;
  /** The title of the renderer as displayed in the legend. */
  title?: string | null;
}

/** Describes the schema of the DotDensityTitle element. */
export interface DotDensityTitle {
  /** The unit. */
  unit?: string | null;
  /** The value. */
  value: number;
}

/** Describes the schema of the ClusterTitle element. */
export interface ClusterTitle {
  /** Whether to show the count. */
  showCount: boolean;
}

/** Describes the schema of the RampTitle element. */
export interface RampTitle {
  /**
   * The field name used in a visual variable of a renderer. This is used in the
   *   generated title of the corresponding ramp in the legend.
   */
  field?: string | null;
  /**
   * If provided, the normalization field name used in a visual variable of a renderer.
   *   This is used in the generated title of the corresponding ramp in the legend.
   */
  normField?: string | null;
  /** If `true`, the legend formats to display the field and normalization field as a ratio. */
  ratio: boolean;
  /** If `true`, the legend formats to display the field and normalization field as a percentage. */
  ratioPercent: boolean;
  /** If `true`, the legend formats to display the field and normalization field as a percentage of total. */
  ratioPercentTotal: boolean;
}

/** Describes the schema of the StretchMultibandTitle element. */
export interface StretchMultibandTitle {
  /** The band name. */
  bandName: string;
  /** The color name. */
  colorName: keyof LegendMessages;
}

/**
 * Describes the schema of the SizeRampStop element. Each SizeRampStop represents a single stop of the
 * [SizeVariable](https://developers.arcgis.com/javascript/latest/api-reference/esri-renderers-visualVariables-SizeVariable.html) referenced in the renderer.
 */
export interface SizeRampStop {
  /** The label in the legend describing features with the given `symbol` and `value`. */
  label: string;
  /** The width of the outline in points. */
  outlineSize?: number | null;
  /** The HTML element rendered in the legend representing features with the given value. */
  preview?: HTMLElement | null;
  /** The size of the visual variable [stop](https://developers.arcgis.com/javascript/latest/api-reference/esri-renderers-visualVariables-ColorVariable.html#stops) in points. */
  size?: number | {
      width: number;
      height: number;
  } | null;
  /** The symbol corresponding to the value of the stop in the renderer. */
  symbol: SymbolUnion;
  /** The value of the size visual variable [stop](https://developers.arcgis.com/javascript/latest/api-reference/esri-renderers-visualVariables-SizeVariable.html#stops). */
  value?: any | null;
}

/**
 * Describes the schema of the ColorRampStop element. Each ColorRampStop represents a single stop of the
 * [ColorVariable](https://developers.arcgis.com/javascript/latest/api-reference/esri-renderers-visualVariables-ColorVariable.html) referenced in the renderer.
 */
export interface ColorRampStop {
  /** The color of the visual variable [stop](https://developers.arcgis.com/javascript/latest/api-reference/esri-renderers-visualVariables-ColorVariable.html#stops). */
  color: Color;
  /** The label in the legend describing features with the given `color` and `value`. */
  label: string | null;
  /** The value of the color visual variable [stop](https://developers.arcgis.com/javascript/latest/api-reference/esri-renderers-visualVariables-ColorVariable.html#stops). */
  value: number | string | null;
}

/**
 * Describes the schema of the OpacityRampStop element. Each OpacityRampStop represents a single stop of the
 * [OpacityVariable](https://developers.arcgis.com/javascript/latest/api-reference/esri-renderers-visualVariables-OpacityVariable.html) referenced in the renderer. The opacity value of
 * each stop is indicated in the [alpha](https://developers.arcgis.com/javascript/latest/api-reference/esri-Color.html#a) property of the `color` object.
 */
export interface OpacityRampStop {
  /**
   * The color of the visual variable [stop](https://developers.arcgis.com/javascript/latest/api-reference/esri-renderers-visualVariables-OpacityVariable.html#stops).
   *   The opacity corresponding to the given `value` is indicated in the [alpha](https://developers.arcgis.com/javascript/latest/api-reference/esri-Color.html#a) property of the color object.
   */
  color: Color;
  /** The label in the legend describing features with the given `color` and `value`. */
  label: string;
  /** The value of the opacity visual variable [stop](https://developers.arcgis.com/javascript/latest/api-reference/esri-renderers-visualVariables-OpacityVariable.html#stops). */
  value: number;
}

/**
 * Describes the schema of the HeatmapRampStop element. Each HeatmapRampStop represents a single `colorStop` of the
 * [Heatmap color stops](https://developers.arcgis.com/javascript/latest/api-reference/esri-renderers-HeatmapRenderer.html#colorStops) referenced in the renderer.
 */
export interface HeatmapRampStop {
  /**
   * The color of the pixel corresponding to the appropriate pixel `ratio`. This value is typically
   *   between `0` and `1`.
   */
  color: Color;
  /**
   * The label of the color stop displayed in the legend. Typically only the first and last
   *   stops have labels.
   */
  label: string;
  /**
   * The ratio of a pixel's intensity value to the minPixelIntensity of the renderer.
   *   The ratio of each pixel is matched to the corresponding color.
   */
  ratio: number;
}

/**
 * Describes the schema of the RelationshipLabels element. These labels are rendered in the corners of the square
 * that represent the relationship renderer in the legend.
 */
export interface RelationshipLabels {
  /**
   * The label corresponding with the bottom corner of the legend if the focus is
   *   set to `HH`. This
   *   describes values that are considered low in both field 1 and field 2 (LL).
   */
  bottom: string;
  /**
   * The label corresponding with the left corner of the legend (if the focus
   *   is set to `HH`). This describes features where the value of field 1 is high and the value of field 2 is low (HL).
   */
  left: string;
  /**
   * The label corresponding with the right corner of the legend (if the focus
   *   is set to `HH`). This describes features where the value of field 2 is high and the value of field 1 is low (LH).
   */
  right: string;
  /**
   * The label corresponding with the top corner of the legend if the focus
   *   is set to `HH`. This
   *   describes values that are considered high in both field 1 and field 2 (HH).
   */
  top: string;
}

/** The following properties define an attribution item that contains the attribution text for a layer. */
export interface AttributionItem {
  /** The layer view that has the attribution text. */
  readonly layerView: LayerView;
  /** The attribution text. */
  readonly text: string;
}

export type MeasurementState = "disabled" | "ready" | "measuring" | "measured";

export interface AreaMeasurement {
  /** The area (m²). */
  area: number;
  /** Measurement area. */
  geometry: Polygon;
  /** The perimeter (m). */
  perimeter: number;
}

export interface AreaMeasurementLabel {
  /** The area (m²). */
  area: string;
  /** The perimeter (m). */
  perimeter: string;
}

export interface LinearMeasurement {
  /** Measurement line. */
  geometry: Polyline;
  /** Line length (m). */
  length: number;
}

/** A dom node owner. */
export interface DomNodeOwner {
  /** The dom node. */
  domNode: HTMLElement;
}

export type SliderFormatType = "average" | "min" | "max" | "tick" | "value";

/**
 * Function used to format labels. This function should be set to the
 * [Histogram#labelFormatFunction](https://developers.arcgis.com/javascript/latest/api-reference/esri-widgets-Histogram.html#labelFormatFunction) property. This function fires
 * every time a label is created or updated on the histogram.
 *
 * @param value - The value for the line on the data axis.
 * @param type - The label type. Currently, the only supported type is `average`.
 * @param index - The index of the data line.
 * @returns The formatted value of the label.
 */
export type HistogramLabelFormatFunction = (value: number, type?: "average", index?: number) => string;

/**
 * Function used to format labels. This function should be set to the
 * [Slider#labelFormatFunction](https://developers.arcgis.com/javascript/latest/api-reference/esri-widgets-Slider.html#labelFormatFunction) property. It fires
 * each time a label is created or updated on the slider.
 *
 * @param value - The value of the thumb to be labeled.
 * @param type - The label type. Valid types include `average`, `min`, `max`, `tick`, and `value`.
 * @param index - The index of the thumb (or [value](https://developers.arcgis.com/javascript/latest/api-reference/esri-widgets-Slider.html#values)).
 * @returns The formatted value of the label.
 */
export type LabelFormatFunction = (value: number, type?: SliderFormatType, index?: number) => string;

/**
 * Function used to format thumb labels. This function should be set to the
 * [SmartMappingSliderBase#labelFormatFunction](https://developers.arcgis.com/javascript/latest/api-reference/esri-widgets-smartMapping-SmartMappingSliderBase.html#labelFormatFunction) property. This function fires
 * every time a label is created or updated on the slider.
 *
 * @param value - The value of the thumb.
 * @param type - The label type. Valid types include `average`, `min`, `max`, and `value`.
 * @param index - The index of the thumb (or {@link widgets/smartMapping/SmartMappingSliderBase#values value}).
 * @returns The formatted value for the label.
 */
export type InputFormatFunction = LabelFormatFunction;

/**
 * Function definition for the
 * [Slider#inputParseFunction](https://developers.arcgis.com/javascript/latest/api-reference/esri-widgets-Slider.html#inputParseFunction) property. It fires
 * each time the user modifies slider input by key entry.
 *
 * @param value - The formatted input value of the thumb to be parsed.
 * @param type - The label type. Valid types include `average`, `min`, `max`, `tick`, and `value`.
 * @param index - The index of the thumb (or [value](https://developers.arcgis.com/javascript/latest/api-reference/esri-widgets-Slider.html#values)).
 * @returns The parsed number value of the thumb.
 */
export type InputParseFunction = (value: string, type?: "average" | "min" | "max" | "tick" | "value", index?: number) => number;