import type Extent from "../../geometry/Extent.js";
import type Point from "../../geometry/Point.js";
import type DimensionalDefinition from "../support/DimensionalDefinition.js";
import type PixelBlock from "../support/PixelBlock.js";
import type { AbortOptions } from "../../core/promiseUtils.js";

/**
 * Specifies how raster values are resampled.
 *
 * @see [FetchRasterOptions](https://developers.arcgis.com/javascript/latest/api-reference/esri-layers-raster-types.html#FetchRasterOptions)
 * @since 5.0
 */
export type RasterInterpolation = "nearest" | "bilinear" | "cubic" | "majority";

/**
 * Defines numeric arrays that can represent raster pixel values.
 *
 * @see [PixelBlock.pixels](https://developers.arcgis.com/javascript/latest/api-reference/esri-layers-support-PixelBlock.html#pixels)
 * @since 5.0
 */
export type BandValuesArray = Int8Array<ArrayBuffer> | Uint8Array<ArrayBuffer> | Uint8ClampedArray<ArrayBuffer> | Int16Array<ArrayBuffer> | Uint16Array<ArrayBuffer> | Int32Array<ArrayBuffer> | Uint32Array<ArrayBuffer> | Float32Array<ArrayBuffer> | Float64Array<ArrayBuffer> | number[];

/**
 * The pixel type.
 *
 * @see [PixelBlock.pixelType](https://developers.arcgis.com/javascript/latest/api-reference/esri-layers-support-PixelBlock.html#pixelType)
 * @since 5.0
 */
export type RasterPixelType = "unknown" | "u1" | "u2" | "u4" | "u8" | "s8" | "u16" | "s16" | "u32" | "s32" | "f32" | "f64" | "c64" | "c128";

/**
 * The common output pixel type.
 *
 * @since 5.0
 */
export type RasterCommonPixelType = "unknown" | "u8" | "s8" | "u16" | "s16" | "u32" | "s32" | "f32" | "f64";

/**
 * Lists supported output formats for imagery export and requests.
 *
 * @see [ImageryLayer.format](https://developers.arcgis.com/javascript/latest/api-reference/esri-layers-ImageryLayer.html#format)
 * @since 5.0
 */
export type RasterFormats = "lerc" | "jpg" | "jpgpng" | "png" | "png8" | "png24" | "png32" | "bip" | "bsq" | "tiff" | "bmp" | "gif";

/**
 * Specifies how NoData values are interpreted across multiple bands.
 *
 * @see [ImageryLayer.noDataInterpretation](https://developers.arcgis.com/javascript/latest/api-reference/esri-layers-ImageryLayer.html#noDataInterpretation)
 * @since 5.0
 */
export type RasterNoDataInterpretation = "any" | "all";

/**
 * Identifies the category of raster data returned by an imagery source.
 *
 * @see [RasterInfo.dataType](https://developers.arcgis.com/javascript/latest/api-reference/esri-layers-support-RasterInfo.html#dataType)
 * @since 5.0
 */
export type RasterDataType = "generic" | "elevation" | "thematic" | "processed" | "scientific" | "standard-time" | "vector-uv" | "vector-u" | "vector-v" | "vector-magdir" | "vector-magnitude" | "vector-direction";

/**
 * Describes pixel size along the x and y axes.
 *
 * @see [RasterInfo.pixelSize](https://developers.arcgis.com/javascript/latest/api-reference/esri-layers-support-RasterInfo.html#pixelSize)
 * @since 5.0
 */
export interface PixelSize {
  /**
   * Pixel size along the x axis.
   *
   * @since 5.0
   */
  x: number;
  /**
   * Pixel size along the y axis.
   *
   * @since 5.0
   */
  y: number;
}

/**
 * Data series returned in [RasterIdentifyResult](https://developers.arcgis.com/javascript/latest/api-reference/esri-layers-raster-types.html#RasterIdentifyResult) when [ImageryTileLayer.identify()](https://developers.arcgis.com/javascript/latest/api-reference/esri-layers-ImageryTileLayer.html#identify) is called on a
 * transposed multidimensional ImageryTileLayer.
 *
 * @since 4.25
 */
export interface RasterSliceValue {
  /**
   * Image service pixel values for a given slice.
   *
   * @since 5.0
   */
  value?: number[] | null;
  /**
   * A dimensional definition associated with a given slice.
   *
   * @since 5.0
   */
  multidimensionalDefinition: DimensionalDefinition[];
  /**
   * The magnitude and direction values for services containing vector data.
   *
   * @since 5.0
   */
  magdirValue?: [
      number,
      number
  ];
}

/**
 * The result of `identify` operation on [ImageryTileLayer.identify()](https://developers.arcgis.com/javascript/latest/api-reference/esri-layers-ImageryTileLayer.html#identify) and [WCSLayer.identify()](https://developers.arcgis.com/javascript/latest/api-reference/esri-layers-WCSLayer.html#identify).
 * It includes the processed pixel values for a given location.
 *
 * @since 5.0
 */
export interface RasterIdentifyResult {
  /**
   * The identified location.
   *
   * @since 5.0
   */
  location: Point;
  /**
   * Image service pixel values.
   *
   * @since 5.0
   */
  value?: number[] | null;
  /**
   * The processed pixel values showing results of the [ImageryTileLayer.rasterFunction](https://developers.arcgis.com/javascript/latest/api-reference/esri-layers-ImageryTileLayer.html#rasterFunction) applied to the layer. Added since version 4.26.
   *
   * @since 5.0
   */
  processedValue?: number[];
  /**
   * Transposed multidimensional data for the requested location and variable
   * returned from a transposed multidimensional [ImageryTileLayer.identify()](https://developers.arcgis.com/javascript/latest/api-reference/esri-layers-ImageryTileLayer.html#identify). Added since version 4.25.
   *
   * @since 5.0
   */
  dataSeries?: RasterSliceValue[];
}

/**
 * An object that provides the user access to
 * [PixelBlock.pixels](https://developers.arcgis.com/javascript/latest/api-reference/esri-layers-support-PixelBlock.html#pixels) and their values in the layer.
 * See the object specifications table below for details about each property. This object
 * is used as input in the [ImageryLayer.pixelFilter](https://developers.arcgis.com/javascript/latest/api-reference/esri-layers-ImageryLayer.html#pixelFilter) function
 * for filtering and processing each pixel in the block.
 *
 * @see [ArcGISImageService.fetchPixels()](https://developers.arcgis.com/javascript/latest/api-reference/esri-layers-mixins-ArcGISImageService.html#fetchPixels)
 * @since 5.0
 */
export interface PixelData {
  /**
   * The extent of the `pixelBlock`.
   *
   * @since 5.0
   */
  extent: Extent;
  /**
   * An object representing
   *   the pixels in the view. This provides the user access to each pixel on the client
   *   via the pixels property of this object.
   *
   * @since 5.0
   */
  pixelBlock?: PixelBlock | null;
}

/**
 * Raster statistics information returned that meets the specified [ImageHistogramParameters](https://developers.arcgis.com/javascript/latest/api-reference/esri-rest-support-ImageHistogramParameters.html)
 * from the `computeStatisticsHistograms()` method on [ImageryLayer.computeStatisticsHistograms()](https://developers.arcgis.com/javascript/latest/api-reference/esri-layers-ImageryLayer.html#computeStatisticsHistograms) or [ImageryTileLayer.computeStatisticsHistograms()](https://developers.arcgis.com/javascript/latest/api-reference/esri-layers-ImageryTileLayer.html#computeStatisticsHistograms).
 *
 * @since 4.18
 */
export interface RasterBandStatistics {
  /**
   * Minimum value of the statistics.
   *
   * @since 5.0
   */
  min: number;
  /**
   * Maximum value of the statistics.
   *
   * @since 5.0
   */
  max: number;
  /**
   * Average of the statistics.
   *
   * @since 5.0
   */
  avg?: number;
  /**
   * Standard deviation of the statistics.
   *
   * @since 5.0
   */
  stddev?: number;
  /**
   * Mode value of the statistics.
   *
   * @since 5.0
   */
  mode?: number;
  /**
   * Median value of the statistics.
   *
   * @since 5.0
   */
  median?: number;
  /**
   * Sum of the statistics.
   *
   * @since 5.0
   */
  sum?: number;
  /**
   * Count of the statistics.
   *
   * @since 5.0
   */
  count?: number;
}

/**
 * Raster histogram information returned that meets the specified [ImageHistogramParameters](https://developers.arcgis.com/javascript/latest/api-reference/esri-rest-support-ImageHistogramParameters.html)
 * from the [ImageryLayer.computeHistograms()](https://developers.arcgis.com/javascript/latest/api-reference/esri-layers-ImageryLayer.html#computeHistograms) or [ImageryLayer.computeStatisticsHistograms()](https://developers.arcgis.com/javascript/latest/api-reference/esri-layers-ImageryLayer.html#computeStatisticsHistograms) method.
 *
 * @since 4.18
 */
export interface RasterHistogram {
  /**
   * Number of bins.
   *
   * @since 5.0
   */
  size: number;
  /**
   * The minimum pixel value of the histogram. Matches the minimum bound of the first bin.
   *
   * @since 5.0
   */
  min: number;
  /**
   * The maximum pixel value of the histogram. Matches the maximum bound of the last bin.
   *
   * @since 5.0
   */
  max: number;
  /**
   * Count of pixels that fall into each bin.
   *
   * @since 5.0
   */
  counts: number[] | Uint32Array;
}

/**
 * A dimension may be used to represent real physical dimensions such as time or depth/height. It may also be used to represent more
 * abstract quantities such as station id or station-time pair. For example, if your temperature data has a corresponding Date dimension field representing the day it was captured, and
 * your salinity data has a Depth dimension field representing the depth at which it was measured, the Dimensions field for that variable would be Date and Depth.
 *
 * @since 5.0
 */
export interface RasterDimensionalInfo {
  /**
   * Dimension name.
   *
   * @since 5.0
   */
  name: string;
  /**
   * Dimension description.
   *
   * @since 5.0
   */
  description?: string | null;
  /**
   * Dimension unit.
   *
   * @since 5.0
   */
  unit?: string | null;
  /**
   * An array of single values or tuples [min, max] each defining a range of valid values along the specified dimension.
   *
   * @since 5.0
   */
  values?: (number | [
      number,
      number
  ])[] | null;
  /**
   * Indicates if each dimension value is represented using a range.
   *
   * @since 5.0
   */
  hasRanges?: boolean | null;
  /**
   * Indicates if the dimension is recorded at regular intervals.
   *
   * @since 5.0
   */
  hasRegularIntervals?: boolean | null;
  /**
   * Dimension interval.
   *
   * @since 5.0
   */
  interval?: number | null;
  /**
   * Dimension interval unit.
   *
   * @since 5.0
   */
  intervalUnit?: string | null;
  /**
   * The extent of dimension values.
   *
   * @since 5.0
   */
  extent?: number[];
  /**
   * Indicates if the dimension is recurring, e.g. data with 12 slices each represents aggregated value per month over the years.
   *
   * @since 5.0
   */
  recurring?: boolean | null;
}

/**
 * RasterMultidimensionalInfo contains dimensions for each variable in the service  describing information about the images collected at multiple times, depths, or heights.
 *
 * @since 5.0
 * @example
 * // update the statistics of the layer's stretch renderer.
 * const renderer = layer.renderer.clone();
 *  const dimensions = layer.rasterInfo.multidimensionalInfo;
 * // get the salinity variable's statistics
 * const salinity = dimensions.variables.find((variable) => variable.name === variableName);
 * renderer.customStatistics = salinity.statistics;
 * layer.renderer = renderer;
 */
export interface RasterMultidimensionalInfo {
  /**
   * The multi dimensional variables. It stores information such as name, unit and dimensions. For example, a temperature variable can store
   * temperature data and the salinity variable can store the salinity data measured daily at different depths.
   *
   * @since 5.0
   */
  variables: RasterMultidimensionalInfoVariable[];
}

/**
 * Describes a variable in multidimensional raster data.
 *
 * @since 5.0
 */
export interface RasterMultidimensionalInfoVariable {
  /**
   * Variable name.
   *
   * @since 5.0
   */
  name: string;
  /**
   * A dimension may be used to represent real physical dimensions such as time or depth/height. It may also be used to represent more
   * abstract quantities such as station id or station-time pair. For example, if your temperature data has a corresponding Date dimension field representing the day it was captured, and
   * your salinity data has a Depth dimension field representing the depth at which it was measured, the Dimensions field for that variable would be Date and Depth.
   *
   * @since 5.0
   */
  dimensions: RasterDimensionalInfo[];
  /**
   * Variable description.
   *
   * @since 5.0
   */
  description?: string | null;
  /**
   * Variable histograms.
   *
   * @since 5.0
   */
  histograms?: RasterHistogram[] | null;
  /**
   * Variable statistics.
   *
   * @since 5.0
   */
  statistics?: RasterBandStatistics[] | null;
  /**
   * Unit of the variable measured in.
   *
   * @since 5.0
   */
  unit?: string | null;
}

/**
 * The raster function published with the image service.
 *
 * @see [ArcGISImageService.rasterFunctionInfos](https://developers.arcgis.com/javascript/latest/api-reference/esri-layers-mixins-ArcGISImageService.html#rasterFunctionInfos)
 * @since 5.0
 */
export interface ServiceRasterFunctionInfo {
  /**
   * Name of the raster function.
   *
   * @since 5.0
   */
  name: string;
  /**
   * Description of the raster function.
   *
   * @since 5.0
   */
  description: string;
  /**
   * Additional info describing what the raster function does.
   *
   * @since 5.0
   */
  help: string;
  /**
   * The function type. Possible values: //0 = Mosaic, 1 = Item, 2 = Item Group.
   *
   * @since 5.0
   */
  functionType: number;
  /**
   * Inline base64 encoded thumbnail of the raster function.
   *
   * @since 5.0
   */
  thumbnail: string;
}

/**
 * Options for fetching raster pixel data from imagery tile layers.
 *
 * @see [ImageryTileLayer.fetchTile()](https://developers.arcgis.com/javascript/latest/api-reference/esri-layers-ImageryTileLayer.html#fetchTile)
 * @see [ImageryTileLayer.fetchPixels()](https://developers.arcgis.com/javascript/latest/api-reference/esri-layers-ImageryTileLayer.html#fetchPixels)
 * @see [WCSLayer.fetchPixels()](https://developers.arcgis.com/javascript/latest/api-reference/esri-layers-WCSLayer.html#fetchPixels)
 * @since 5.0
 */
export interface FetchRasterOptions extends AbortOptions {
  /**
   * Returns pixel data only for the specified bands, if provided. Added at version 4.34.
   *
   * @since 5.0
   */
  bandIds?: number[] | null;
  /**
   * Added at version 4.23. Defines how to interpolate pixel values.
   *
   * @since 5.0
   */
  interpolation?: RasterInterpolation;
}

/**
 * Options for fetching raster pixel data from dynamic imagery services.
 *
 * @see [ImageryLayer.fetchPixels()](https://developers.arcgis.com/javascript/latest/api-reference/esri-layers-ImageryLayer.html#fetchPixels)
 * @since 5.0
 */
export interface DynamicFetchRasterOptions extends AbortOptions {
  /**
   * Returns pixel data only for the specified bands, if provided. Added at version 4.34.
   *
   * @since 5.0
   */
  bandIds?: number[];
  /**
   * Defines how to interpolate pixel values.
   *
   * @since 5.0
   */
  interpolation?: RasterInterpolation;
  /**
   * When `true`, request a rendered image from server using layer's rendering configuration, including
   * layer format (jpgpng or similar), renderer, bandIds, compression quality and interpolation setting.
   *
   * @since 5.0
   */
  applyRendering?: boolean;
}

/**
 * Additional options to set for `identify()` method on [ImageryTileLayer.identify()](https://developers.arcgis.com/javascript/latest/api-reference/esri-layers-ImageryTileLayer.html#identify) and [WCSLayer.identify()](https://developers.arcgis.com/javascript/latest/api-reference/esri-layers-WCSLayer.html#identify).
 *
 * At version 4.25, the `transposedVariableName` was added to get pixel values from specific dimensional definitions if the [ImageryTileLayer](https://developers.arcgis.com/javascript/latest/api-reference/esri-layers-ImageryTileLayer.html)
 * references a [transposed multidimensional](https://developers.arcgis.com/javascript/latest/api-reference/esri-layers-support-RasterInfo.html#hasMultidimensionalTranspose) image service.
 * Set the `transposedVariableName` and `multidimensionalDefinition` get pixel values for the specified dimensional definitions from a transposed multidimensional service.
 * If `multidimensionalDefinition` is not specified, pixel values will be returned from all the dimensional slices.
 *
 * @since 5.0
 */
export interface RasterIdentifyOptions extends AbortOptions {
  /**
   * A dimensional definition used for the `identify` operation.
   * For non-transposed multidimensional [ImageryTileLayer.identify()](https://developers.arcgis.com/javascript/latest/api-reference/esri-layers-ImageryTileLayer.html#identify) and for [WCSLayer.identify()](https://developers.arcgis.com/javascript/latest/api-reference/esri-layers-WCSLayer.html#identify), the identify
   * operation returns a value for only one dimensional slice at a time.
   * For transposed multidimensional [ImageryTileLayer](https://developers.arcgis.com/javascript/latest/api-reference/esri-layers-ImageryTileLayer.html), identify returns values for all or specified dimensional slices.
   *
   * @since 5.0
   */
  multidimensionalDefinition?: DimensionalDefinition[] | null;
  /**
   * Name of the transposed variable. This option is only honored if the ImageryTileLayer's
   * [serviceRasterInfo.hasMultidimensionalTranspose](https://developers.arcgis.com/javascript/latest/api-reference/esri-layers-support-RasterInfo.html#hasMultidimensionalTranspose) is `true`. Added since 4.25.
   *
   * @since 5.0
   */
  transposedVariableName?: string;
}