import type { Color as ColorJSON } from "./portal/jsonTypes.js";

/** Additional options to set when converting a Color to a hexadecimal string via [toHex()](https://developers.arcgis.com/javascript/latest/api-reference/esri-Color.html#toHex) method. */
export interface HexOutputOptions {
  /**
   * When `true`, the hexadecimal number will be capitalized.
   *
   * @default false
   */
  capitalize?: boolean;
  /**
   * The intended size of the output hexadecimal number.
   *                                         Valid values are 3, 4, 6 and 8. The default value is 6.
   *                                         Values 3 and 4 represent the shortened variant.
   *                                         Values 4 and 8 include an alpha channel.
   *
   * @default 6
   */
  digits?: 3 | 4 | 6 | 8;
}

/**
 * The color to create. This parameter can be a string representing a named color or a hex value; an array of three or four numbers representing r, g, b, a values; or an object with r, g, b,
 * a properties.
 *
 * @see [Color constructor](https://developers.arcgis.com/javascript/latest/api-reference/esri-Color.html#constructors-summary)
 */
export type ColorLike = string | readonly number[] | ColorJSON | RGBA;

/** A 4-component array of rgba values that represent the Color instance. */
export interface RGBA {
  /** The red value. This value can range between `0` and `255`. */
  r?: number;
  /** The green value. This value can range between `0` and `255`. */
  g?: number;
  /** The blue value. This value can range between `0` and `255`. */
  b?: number;
  /** The alpha value. This value can be any number between `0` and `1` and represents the opacity of the Color. */
  a?: number;
}

/**
 * Creates a new color object by passing either a hex, rgb(a), hsl(a) or [named color value](https://www.w3.org/wiki/CSS/Properties/color/keywords). Hex, hsl(a) and
 * named color values can be passed as a string:
 *
 * ```js
 * // Examples for green
 * let color = new Color("lime");  // named value
 * let color = new Color("#0f0");  // shortened three digit hexadecimal value
 * let color = new Color("#00ff00");  // six digit hexadecimal value
 * let color = new Color("hsl(120, 100%, 50%)");  // hsl
 * let color = new Color("hsla(120, 100%, 50%, 0.5)"); // hsla
 * ```
 * RGB values can be passed in as either an array, a string or an object:
 *
 * ```js
 * // Examples for green
 * let color = new Color([0, 255, 0]);
 * let color = new Color([0, 255, 0, 0.5]);
 * let color = new Color("rgb(0, 255, 0)");
 * let color = new Color("rgba(0, 255, 0, 0.5)");
 * let color = new Color({r: 0, g: 255, b: 0});
 * let color = new Color({r: 0, g: 255, b: 0, a: 0.5});
 * ```
 *
 * The alpha-channel (opacity) in rgba and hsla can have a value between 0.0 (fully transparent) and 1.0 (fully opaque).
 *
 * @since 4.0
 * @see [Guide - Esri color ramps](https://developers.arcgis.com/javascript/latest/esri-color-ramps/)
 * @see [Guide - Visualization best practices](https://developers.arcgis.com/javascript/latest/visualization-best-practices/)
 */
export default class Color {
  /**
   * Creates a Color instance by blending two colors using a weight factor. Optionally accepts
   * a Color object to update and return instead of creating a new object.
   *
   * @param start - The start color.
   * @param end - The end color.
   * @param weight - The weight value is a number from 0 to 1, with 0.5 being a 50/50 blend.
   * @param out - A previously allocated Color object to reuse for the result.
   * @returns Returns a new Color object.
   * @example
   * const startColor = new Color("#0000ff");
   * const endColor = new Color("#ca0013");
   * const blendedColor = Color.blendColors(startColor, endColor, 0.5);
   */
  static blendColors(start: Color, end: Color, weight: number, out?: Color): Color;
  /**
   * Creates a Color instance using a 3 or 4 element array, mapping each element in sequence to
   * the rgb(a) values of the color. Optionally accepts a Color object to update with the color
   * value and return instead of creating a new object.
   *
   * @param a - The input array.
   * @param t - A previously allocated Color object to reuse for the result.
   * @returns Returns a new Color object.
   * @example let redColor = Color.fromArray([201, 0, 19]);
   */
  static fromArray(a: ColorJSON | readonly number[], t?: Color): Color;
  /**
   * Creates a Color from hexadecimal string.
   *
   * Colors can be expressed as:
   * 1. Hex triplet, a six or eight digit hexadecimal number. For example:
   *    - "#ffff00" for Yellow, or
   *    - "#dc143c20" for a semi-transparent Crimson
   * 2. Shorthand variant, a three or four digit hexadecimal number. For example:
   *    - "#F0F" for Fuchsia, or
   *    - "#FFF8" for semi-transparent white
   *
   * Hexadecimal numbers must be prefixed with the number (or "hash") sign (#). Strings can be upper or lower case.
   *
   * This static method returns a new Color object. Optionally the method accepts an existing color instance that is
   * updated and returned.
   *
   * @param hex - The input color in a hexadecimal string.
   * @param out - A previously allocated Color object to reuse for the result.
   * @returns Returns a new Color object or updated color object (if parsed).
   * @example
   * const red = Color.fromHex("#ff0000");     // Color from hex triplet
   * const blue = Color.fromHex("#00F");       // Color from hex shorthand
   * const green = Color.fromHex("#00ff0080"); // Color with 50% transparency
   */
  static fromHex(hex: string, out?: Color): Color | null | undefined;
  /**
   * Creates a new Color instance, and initializes it with values from a JSON object.
   *
   * @param json - A JSON representation of the instance.
   * @returns A new Color instance.
   */
  static fromJSON(json: ColorJSON | null | undefined): Color | null | undefined;
  /**
   * Creates a Color instance from a string of the form "rgb()" or "rgba()". Optionally accepts a
   * Color object to update with the parsed value and return instead of creating a new object.
   *
   * @param color - The input color in a string of the form "rgb()" or "rgba()".
   * @param out - A previously allocated Color object to reuse for the result.
   * @returns Returns a new Color object.
   * @example const redColor = Color.fromRgb("rgb(202,0,19)");
   */
  static fromRgb(color: string, out?: Color): Color | null | undefined;
  /**
   * Creates a Color instance by parsing a generic string. Accepts hex, rgb, and rgba style color
   * values. Optionally accepts a Color object to update with the parsed value and return instead
   * of creating a new object.
   *
   * @param color - The input value.
   * @param obj - A previously allocated Color object to reuse for the result.
   * @returns Returns a new Color object.
   * @example let blueColor = Color.fromString("blue");
   */
  static fromString(color: string, obj?: Color): Color | null | undefined;
  /**
   * @example
   * // Creates a green Color object using a named value
   * let color = new Color("green");
   *
   * // Creates a green Color object using a hex value
   * let color = new Color("#00ff00");
   *
   * // Creates a new Color object using an array of r, g, b values
   * let color = new Color([125, 255, 13]);
   *
   * // Add a fourth value to the array to add opacity (range between 0 and 1)
   * let color = new Color([125, 255, 13, 0.5]);
   *
   * // Creates a new Color object using an object
   * let color = new Color({
   *   r: 125,
   *   g: 255,
   *   b: 13,
   *   a: 0.3  // Optional
   * });
   */
  constructor(color?: ColorLike);
  /**
   * The alpha value. This value can be any number between `0` and `1` and represents the opacity of the Color.
   * `0` indicates the color is fully transparent and `1` indicates it is fully opaque.
   *
   * @default 1
   */
  a: number;
  /**
   * The blue value. This value can range between `0` and `255`.
   *
   * @default 255
   */
  b: number;
  /**
   * The green value. This value can range between `0` and `255`.
   *
   * @default 255
   */
  g: number;
  /**
   * The red value. This value can range between `0` and `255`.
   *
   * @default 255
   */
  r: number;
  /**
   * Creates a deep clone of the Color instance.
   *
   * @returns A deep clone of the Color instance.
   * @example
   * // Creates a deep clone of the graphic's color
   * let colorClone = graphic.symbol.color.clone();
   */
  clone(): Color;
  /**
   * Checks equality of the Color instance with another Color instance.
   *
   * @param other - Another color, or null or undefined.
   * @returns true if the other color is the same as this one (r, g, b, and a values are identical).
   * @since 4.33
   */
  equals(other: Color | null | undefined): boolean;
  /**
   * Takes an array of rgb(a) values, named string, hex string or an hsl(a) string,
   * an object with `r`, `g`, `b`, and `a` properties, or a [Color](https://developers.arcgis.com/javascript/latest/api-reference/esri-Color.html) object
   * and sets this color instance to the input value.
   *
   * @param color - The new color value. This parameter can be a string
   *                                           representing a named color or a hex value; an array of three
   *                                           or four numbers representing r, g, b, a values; or an object
   *                                           with r, g, b, a properties.
   * @returns Sets the Color instance used to call this method to the new color.
   */
  setColor(color: string | ColorLike | ColorJSON | number[]): this;
  /**
   * Returns a CSS color string in rgba form representing the Color instance.
   *
   * @param includeAlpha - If `true`, the alpha value will be included in the result.
   * @returns A CSS color string in rgba form that represents the Color instance used to call this method.
   */
  toCss(includeAlpha?: boolean): string;
  /**
   * Returns the color in hexadecimal format.
   *
   * @param options - Additional options.
   * @returns A three, four, six or eight-digit hexadecimal number.
   * @see [RGB Hexadecimal Notations](https://drafts.csswg.org/css-color/#hex-notation)
   * @example
   * // Three digit notation
   * const hex = Color.fromString("red").toHex({ digits: 3 });                   // returns "#f00"
   * const hex = Color.fromString("red").toHex({ digits: 3, capitalize: true }); // returns "#F00"
   *
   * // Four digit notation
   * const hex = Color.fromString("red").toHex({ digits: 4 });                   // returns "#f00f"
   * const hex = Color.fromString("red").toHex({ digits: 4, capitalize: true }); // returns "#F00F"
   *
   * // Six digit notation
   * const hex = Color.fromString("red").toHex({ digits: 6 });                   // returns "#ff0000"
   * const hex = Color.fromString("red").toHex({ digits: 6, capitalize: true }); // returns "#ff0000"
   *
   * // Eight digit notation
   * const hex = Color.fromString("red").toHex({ digits: 8 });                   // returns "#ff0000ff"
   * const hex = Color.fromString("red").toHex({ digits: 8, capitalize: true }); // returns "#ff0000ff"
   */
  toHex(options?: HexOutputOptions): string;
  /**
   * Returns a JSON object with all the values from a Color instance.
   *
   * @returns A JSON representation of the Color instance.
   */
  toJSON(): ColorJSON;
  /**
   * Returns a 3-component array of rgb values that represent the Color instance.
   *
   * @returns A 3-component array of rgb values.
   */
  toRgb(): [
      number,
      number,
      number
  ];
  /**
   * Returns a 4-component array of rgba values that represent the Color instance.
   *
   * @returns A 4-component array of rgba values.
   */
  toRgba(): [
      number,
      number,
      number,
      number
  ];
}