import type { LabelFormatFunction } from "../types.js";

/**
 * Represents the effective bounds of the slider.
 *
 * @since 5.0
 */
export interface Bounds {
  /**
   * The effective min value of the slider, or the minimum value a user can set a thumb on the slider.
   *
   * @since 5.0
   */
  min?: number | null;
  /**
   * The effective max value of the slider, or the maximum value a user can set a thumb on the slider.
   *
   * @since 5.0
   */
  max?: number | null;
}

/**
 * Label infos for the slider.
 *
 * @since 5.0
 */
export interface LabelInfos {
  /**
   * The label for the maximum value.
   *
   * @since 5.0
   */
  max?: string | null;
  /**
   * The label for the minimum value.
   *
   * @since 5.0
   */
  min?: string | null;
  /**
   * The labels for the values.
   *
   * @since 5.0
   */
  values: (string | null | undefined)[];
}

/** @since 5.0 */
export type InputType = "max" | "min" | "thumb";

/** @since 5.0 */
export type SliderTickMode = "count" | "percent" | "step" | "position";

/**
 * Function that fires each time a tick is created. It provides you access to each tick
 * element so you can add custom CSS and attach event listeners to individual ticks. This function should be set to the
 * `tickCreatedFunction` property of the [TickConfig](https://developers.arcgis.com/javascript/latest/api-reference/esri-widgets-Slider-types.html#TickConfig).
 *
 * @param value - The value of the slider where the tick is rendered.
 * @param tickElement - The HTMLElement representing the tick. You can add or modify the default style of individual
 *   ticks by adding CSS classes to this element. You can also add custom behavior to ticks by attaching
 *   event listeners to individual elements.
 * @param labelElement - The HTMLElement representing the label of the tick. You can add or modify the default
 *   style of the tick's labels by adding CSS classes to this element. You can also add custom behavior to tick labels by attaching
 *   event listeners to individual elements.
 * @since 5.0
 */
export type TickCreatedFunction = (value: number, tickElement?: HTMLElement | null, labelElement?: HTMLElement | null) => void;

/**
 * Function that executes each time a thumb is created on the slider. This function should be set to the
 * [Slider.thumbCreatedFunction](https://developers.arcgis.com/javascript/latest/api-reference/esri-widgets-Slider.html#thumbCreatedFunction) property.
 *
 * @param index - The index of the thumb when the Slider was constructed.
 * @param value - The value of the slider where the thumb is rendered.
 * @param thumbElement - The HTMLElement representing the thumb. You can add or modify the default style of individual
 *   thumbs by adding CSS classes to this element. You can also add custom behavior to thumbs by attaching
 *   event listeners to individual elements.
 * @param labelElement - The HTMLElement representing the label of the thumb. You can add or modify the default
 *   style of the thumb's labels by adding CSS classes to this element. You can also add custom behavior to thumb labels by attaching
 *   event listeners to individual elements.
 * @since 5.0
 */
export type ThumbCreatedFunction = (index: number, value: number, thumbElement: HTMLElement, labelElement?: HTMLElement | null) => void;

/**
 * Function that executes each time an input element is created. It allows the developer to validate
 * a user's manually entered slider thumb values. This function should be set to the
 * [Slider.inputCreatedFunction](https://developers.arcgis.com/javascript/latest/api-reference/esri-widgets-Slider.html#inputCreatedFunction) property.
 *
 * @param inputElement - The HTMLInputElement allowing the user to manually input
 *   slider thumb values. You can customize this element to validate user input, for example by setting
 *   the `type` and `pattern` attributes.
 * @param type - The type of input created.
 * @param thumbIndex - The index of the thumb corresponding to the input element.
 * @since 5.0
 */
export type InputCreatedFunction = (inputElement: HTMLInputElement, type: InputType, thumbIndex?: number | null) => void;

/**
 * Object specification for configuring ticks on the slider. An array of these objects should be set on the
 * [Slider.tickConfigs](https://developers.arcgis.com/javascript/latest/api-reference/esri-widgets-Slider.html#tickConfigs) property.
 *
 * @since 5.0
 * @example
 * // places 25 ticks on the slider track
 * // evenly spaced from one another
 * slider.tickConfigs = [{
 *   mode: "count",
 *   values: 25
 * }];
 * @example
 * // places ticks spanning the width of
 * // the slider at 20% intervals from one another
 * // this is the equivalent of setting mode to 'count'
 * // and the values to 5.
 * slider.tickConfigs = [{
 *   mode: "percent",
 *   values: 20
 * }];
 * @example
 * // Places three ticks on the slider: one positioned
 * // 10% of the width from the start (or min value), another
 * // directly in the middle (50% from the start), and
 * // another 90% of the width from the start of the slider.
 * // Because the values are %s the values are always relative
 * // regardless of the range of the slider values.
 * slider.tickConfigs = [{
 *   mode: "percent",
 *   values: [ 10, 50, 90 ]
 * }];
 * @example
 * // Places 5 ticks on the slider at the slider values
 * // provided below. These are absolute positions.
 * slider.tickConfigs = [{
 *   mode: "position",
 *   values: [ 0, 5, 10, 15, 20 ]
 * }];
 * @example
 * // Places a single tick at the location of the value of 5.
 * slider.tickConfigs = [{
 *   mode: "position",
 *   values: 5
 * }];
 * @example
 * // Renders three groups of ticks. The first is a basic set
 * // of 25 ticks. The second places 4 ticks and adds custom
 * // CSS classes to modify their styling. The third adds
 * // a click event handler to the tick labels.
 * slider.tickConfigs = [{
 *   mode: "count",
 *   values: 25
 * }, {
 *   mode: "percent",
 *   values: [12.5, 37.5, 62.5, 87.5],
 *   labelsVisible: true,
 *   tickCreatedFunction: function(initialValue, tickElement, labelElement) {
 *     tickElement.classList.add("mediumTicks");
 *     labelElement.classList.add("mediumLabels");
 *   }
 * }, {
 *   mode: "count",
 *   values: 5,
 *   labelsVisible: true,
 *   tickCreatedFunction: function(initialValue, tickElement, labelElement) {
 *     tickElement.classList.add("largeTicks");
 *     labelElement.classList.add("largeLabels");
 *     labelElement.onclick = function() {
 *       const newValue = labelElement["data-value"];
 *       slider.values = [ newValue ];
 *     };
 *   }
 * }];
 */
export interface TickConfig {
  /**
   * The mode or method of positioning ticks along the slider track. See the table below for a list of possible values.
   *
   * Possible Value | Description
   * ---------------|------------
   * count | Places a fixed number of ticks (provided in the `values` property) at equal distances from each other below the slider track.
   * percent | When set, and a single number is set on the `values` property, ticks will be placed at the specified percentage interval along the length of the slider. For example, when `mode` is percent and `values` is `5`, then 20 ticks will be placed below the slider track (at 5-percent intervals from each other). If an array of `values` is provided, the values are interpreted as percentages along the slider. So if `values` is `[10, 50, 90]`, then three ticks will be placed below the track; one at the midway point, and two 10 percent of the length from either end of the slider.
   * position | Indicates that ticks will only be placed at the values specified in the `values` property.
   *
   * @since 5.0
   */
  mode: SliderTickMode;
  /**
   * Indicates where ticks will be rendered below the track. See the description for `mode` for more information about how this property is interpreted by each mode.
   *
   * @since 5.0
   */
  values: number | number[];
  /**
   * Indicates whether to render labels for the ticks.
   *
   * @since 5.0
   */
  labelsVisible?: boolean;
  /**
   * Callback that fires for each tick. You can override default behaviors and styles with this property.
   *
   * @since 5.0
   */
  tickCreatedFunction?: TickCreatedFunction;
  /**
   * Callback for formatting tick labels.
   *
   * @since 5.0
   */
  labelFormatFunction?: LabelFormatFunction;
}

/** @since 5.0 */
export interface MaxChangeEvent {
  /**
   * The former [Slider.max](https://developers.arcgis.com/javascript/latest/api-reference/esri-widgets-Slider.html#max) value (or bound) of the slider.
   *
   * @since 5.0
   */
  oldValue: number;
  /**
   * The type of the event.
   *
   * @since 5.0
   */
  type: "max-change";
  /**
   * The value of the [Slider.max](https://developers.arcgis.com/javascript/latest/api-reference/esri-widgets-Slider.html#max) (or bound) of the slider when the event is emitted.
   *
   * @since 5.0
   */
  value: number;
}

/** @since 5.0 */
export interface MinChangeEvent {
  /**
   * The former [Slider.min](https://developers.arcgis.com/javascript/latest/api-reference/esri-widgets-Slider.html#min) value (or bound) of the slider.
   *
   * @since 5.0
   */
  oldValue: number;
  /**
   * The type of the event.
   *
   * @since 5.0
   */
  type: "min-change";
  /**
   * The the [Slider.min](https://developers.arcgis.com/javascript/latest/api-reference/esri-widgets-Slider.html#min) value (or bound) of the slider when the event is emitted.
   *
   * @since 5.0
   */
  value: number;
}

/** @since 5.0 */
export interface MaxClickEvent {
  /**
   * The type of the event.
   *
   * @since 5.0
   */
  type: "max-click";
  /**
   * The max value of the slider.
   *
   * @since 5.0
   */
  value: number;
}

/** @since 5.0 */
export interface MinClickEvent {
  /**
   * The type of the event.
   *
   * @since 5.0
   */
  type: "min-click";
  /**
   * The  min value of the slider.
   *
   * @since 5.0
   */
  value: number;
}

/** @since 5.0 */
export interface ThumbClickEvent {
  /**
   * The 0-based index of the thumb.
   *
   * @since 5.0
   */
  index: number;
  /**
   * The type of the event.
   *
   * @since 5.0
   */
  type: "thumb-click";
  /**
   * The value of the thumb when the event is emitted.
   *
   * @since 5.0
   */
  value: number;
}

/** @since 5.0 */
export interface ThumbChangeEvent {
  /**
   * The 0-based index of the updated thumb position.
   *
   * @since 5.0
   */
  index: number;
  /**
   * The former value of the thumb before the change was made.
   *
   * @since 5.0
   */
  oldValue: number;
  /**
   * The type of the event.
   *
   * @since 5.0
   */
  type: "thumb-change";
  /**
   * The value of the thumb when the event is emitted.
   *
   * @since 5.0
   */
  value: number;
}

/** @since 5.0 */
export interface ThumbDragEvent {
  /**
   * The 0-based index of the updated thumb position.
   *
   * @since 5.0
   */
  index: number;
  /**
   * The state of the drag.
   *
   * @since 5.0
   */
  state: "start" | "drag" | "stop";
  /**
   * The type of the event.
   *
   * @since 5.0
   */
  type: "thumb-drag";
  /**
   * The value of the thumb when the event is emitted.
   *
   * @since 5.0
   */
  value: number;
}

/** @since 5.0 */
export interface TickClickEvent {
  /**
   * The approximate value that the tick represents on the slider track.
   *
   * @since 5.0
   */
  value: number;
  /**
   * The type of the event.
   *
   * @since 5.0
   */
  type: "tick-click";
  /**
   * The 0-based index of the associated configuration provided in [Slider.tickConfigs](https://developers.arcgis.com/javascript/latest/api-reference/esri-widgets-Slider.html#tickConfigs).
   *
   * @since 5.0
   */
  configIndex: number;
  /**
   * The 0-based index of the tick and/or group (associated label) relative to other ticks in the same configuration.
   *
   * @since 5.0
   */
  groupIndex: number;
}

/** @since 5.0 */
export interface TrackClickEvent {
  /**
   * The approximate value of the slider at the location of the click event.
   *
   * @since 5.0
   */
  value: number;
  /**
   * The type of the event.
   *
   * @since 5.0
   */
  type: "track-click";
}

/** @since 5.0 */
export interface SegmentClickEvent {
  /**
   * The 1-based index of the segment on the slider.
   *
   * @since 5.0
   */
  index: number;
  /**
   * The indices of the thumbs on each end of the segment.
   *
   * @since 5.0
   */
  thumbIndices: [
      number,
      number
  ];
  /**
   * The type of the event.
   *
   * @since 5.0
   */
  type: "segment-click";
  /**
   * The approximate value of the slider at the location of the click event.
   *
   * @since 5.0
   */
  value: number;
}

/** @since 5.0 */
export interface SegmentDragEvent {
  /**
   * The 1-based index of the segment in the slider.
   *
   * @since 5.0
   */
  index: number;
  /**
   * The state of the drag.
   *
   * @since 5.0
   */
  state: "start" | "drag" | "stop";
  /**
   * The indices of the thumbs on each end of the segment.
   *
   * @since 5.0
   */
  thumbIndices: [
      number,
      number
  ];
  /**
   * The type of the event.
   *
   * @since 5.0
   */
  type: "segment-drag";
}