import type { JSONSupport } from "../../core/JSONSupport.js";
import type { BandValuesArray, RasterPixelType } from "../raster/types.js";

export interface PixelBlockProperties extends Partial<Pick<PixelBlock, "bandMasks" | "height" | "mask" | "maskIsAlpha" | "pixels" | "pixelType" | "statistics" | "validPixelCount" | "width">> {}

/**
 * An object representing the pixel arrays in the view. It stores and decodes source data
 * fetched from an image service associated with an [ImageryLayer](https://developers.arcgis.com/javascript/latest/references/core/layers/ImageryLayer/). This provides the
 * user access to each pixel on the client via the [pixels](https://developers.arcgis.com/javascript/latest/references/core/layers/support/PixelBlock/#pixels) property.
 * The PixelBlock object is designed to handle generic pixel arrays from any raster data source.
 *
 * @since 4.0
 * @see [ImageryLayer](https://developers.arcgis.com/javascript/latest/references/core/layers/ImageryLayer/)
 * @see [Sample - Access pixel values in an ImageryLayer](https://developers.arcgis.com/javascript/latest/sample-code/layers-imagery-pixelvalues/)
 */
export default class PixelBlock extends JSONSupport {
  constructor(properties?: PixelBlockProperties);
  /** Masks for each band. 0 means noData. */
  accessor bandMasks: Uint8Array<ArrayBuffer>[] | null | undefined;
  /** The height (or number of rows) of the PixelBlock in pixels. */
  accessor height: number;
  /** An array of nodata mask. All pixels are valid when mask is null. */
  accessor mask: Uint8Array<ArrayBuffer> | null | undefined;
  /**
   * Indicates whether mask should be used as alpha values. If no (default), a pixel is valid when corresponding mask value is truthy
   *
   * @default false
   */
  accessor maskIsAlpha: boolean;
  /**
   * A two dimensional array representing the pixels from the Image Service
   * displayed on the client. The length of the first dimension is the same as
   * the number of bands in the layer. The length of the second dimension is
   * [height](https://developers.arcgis.com/javascript/latest/references/core/layers/support/PixelBlock/#height) * [width](https://developers.arcgis.com/javascript/latest/references/core/layers/support/PixelBlock/#width). The length of each band is the same. The
   * pixels in each band are arranged row by row in this format:
   * `[p_00, p_10, p_20, ... p_10, p_11, ...]` where `p_xy` is the pixel value
   * at the column `x` and row `y`.
   *
   * @example
   * let pixels = imgLyr.pixelData.pixelBlock.pixels;
   * // Prints the number of bands in the layer
   * console.log(pixels.length);
   * // An array containing all the pixels in the first band
   * let band1 = pixels[0];
   */
  accessor pixels: BandValuesArray[];
  /**
   * The pixel type. Currently pixel block only supports pixels in "u8", "s8", "u16", "s16", "u32", "s32", "f32", "f64" types.
   *
   * @default "f32"
   */
  accessor pixelType: RasterPixelType;
  /**
   * An array of objects containing numeric statistical properties. Each object
   * has the following specification if defined.
   */
  accessor statistics: PixelBlockBandStatistics[] | null | undefined;
  /** Number of valid pixels */
  accessor validPixelCount: number | null | undefined;
  /** The width (or number of columns) of the PixelBlock in pixels. */
  accessor width: number;
  /**
   * Adds another band to the PixelBlock.
   *
   * @param bandData - The data to add to the PixelBlock.
   */
  addData(bandData: PixelBlockBandData): void;
  /**
   * Returns pixels and masks using a single array in bip format
   * (e.g. [p_00_r, p_00_g, p_00_b, p_00_a, p_10_r, p_10_g, p_10_b, p_10_a, .....]).
   * Use this method to get an unsigned 8 bit pixel array.
   * The result can be used to create a webgl texture.
   *
   * @returns An unsigned 8-bit pixel array.
   */
  getAsRGBA(): Uint8ClampedArray<ArrayBuffer>;
  /**
   * Similar to [getAsRGBA()](https://developers.arcgis.com/javascript/latest/references/core/layers/support/PixelBlock/#getAsRGBA), but returns floating point data.
   * The result can be used to create a webgl texture (OES_texture_float).
   *
   * @returns A floating point array.
   */
  getAsRGBAFloat(): Float32Array<ArrayBuffer>;
  /**
   * Returns the plane band count of the PixelBlock.
   *
   * @returns The plane band count.
   */
  getPlaneCount(): number | null | undefined;
}

/** The data to add to the PixelBlock via the [addData()](https://developers.arcgis.com/javascript/latest/references/core/layers/support/PixelBlock/#addData) method. */
export interface PixelBlockBandData {
  /** An array representing the pixel data to add. */
  pixels: number[];
  /** An object containing numeric statistical properties. */
  statistics?: PixelBlockBandStatistics;
}

/**
 * Pixel block band statistics. Returns the minimum and maximum pixel values for a band in a
 * [PixelBlock](https://developers.arcgis.com/javascript/latest/references/core/layers/support/PixelBlock/), as well as the no data value.
 */
export interface PixelBlockBandStatistics {
  /** The minimum pixel value in the [pixels](https://developers.arcgis.com/javascript/latest/references/core/layers/support/PixelBlock/#pixels) array. */
  readonly minValue: number;
  /** The maximum pixel value in the [pixels](https://developers.arcgis.com/javascript/latest/references/core/layers/support/PixelBlock/#pixels) array. */
  readonly maxValue: number;
  /** Value representing areas of no data. */
  readonly noDataValue?: number | null;
}