import type Accessor from "../../../../core/Accessor.js";
import type { TooltipFieldContext, TooltipFieldName } from "../types.js";

/**
 * @internal
 * @since 5.0
 */
export type RequiredProperties<Q> = Pick<TooltipField<Q>, "actual" | "format" | "formatForInputMode" | "parse" | "title">;

/**
 * @internal
 * @since 5.0
 */
export type OptionalProperties<Quantity> = Pick<TooltipField<Quantity>, "committed" | "displayOrder" | "inputValue" | "lockable" | "readOnly" | "suffix" | "unlockOnVertexPlacement" | "visible" | "name">;

/**
 * Tooltip fields can be used to give feedback and/or gather input from the user
 * and are shown in a tooltip. This object holds the state of a field.
 *
 * Instances of [TooltipField](https://developers.arcgis.com/javascript/latest/references/core/views/interactive/tooltip/fields/TooltipField/) should not be created directly.
 * Instead, use the appropriate helper method or callback,
 * for example [PluginContext](https://developers.arcgis.com/javascript/latest/references/core/views/draw/support/types/#PluginContext).`createField`.
 *
 * @internal
 * @since 5.0
 */
export abstract class TooltipField<Quantity = unknown> extends Accessor {
  /**
   * Actual value as computed by the active tool. Numerical feedback is based on this.
   *
   * @internal
   */
  accessor actual: Quantity | null | undefined;
  /**
   * The value which has been committed by the user by locking the field.
   * This property is ignored if [lockable](https://developers.arcgis.com/javascript/latest/references/core/views/interactive/tooltip/fields/TooltipField/#lockable),
   * is `false`. This value should then be applied as a constraint.
   *
   * @internal
   */
  accessor committed: Quantity | null | undefined;
  /**
   * Optional relative display order; useful for controlling presentation
   * when using dynamically generated tooltips. When displayed in a dynamic
   * tooltip, fields are ordered by this value (i.e. lower values shown first).
   *
   * @default 0
   * @internal
   */
  accessor displayOrder: number;
  /**
   * Function which formats a quantity into a string for display in the tooltip when in numerical
   * feedback mode.
   *
   * @internal
   */
  accessor format: (quantity: Quantity, ctx: TooltipFieldContext) => string;
  /**
   * Function which formats a quantity into a string for display in the tooltip when in numerical
   * input mode. It should be in the input units and should not include the unit suffix/abbreviation.
   *
   * @internal
   */
  accessor formatForInputMode: (quantity: Quantity, ctx: TooltipFieldContext) => string;
  /**
   * Value typed by the user in the input.
   *
   * @internal
   */
  accessor inputValue: string | null | undefined;
  /**
   * Whether the field can be locked by specifying a `committed` value.
   *
   * @default true
   * @internal
   */
  accessor lockable: boolean;
  /**
   * Name of the tooltip field, which should identify a known built-in field.
   * See `title` for the property that controls the user-facing name of the field.
   *
   * @internal
   */
  accessor name: TooltipFieldName | null;
  /**
   * Parses a string into a value to be stored in the field.
   *
   * Param: value The string to parse.
   * Param: ctx The context of the tooltip.
   * Returns: The parsed value, or `null` if the value could not be parsed.
   *
   * @internal
   */
  accessor parse: (value: string | null | undefined, ctx: TooltipFieldContext) => Quantity | null;
  /**
   * Whether the field is read-only.
   *
   * @default false
   * @internal
   */
  accessor readOnly: boolean;
  /**
   * A string or a function which returns a string to be displayed as a suffix next to the field
   * input. Typically used to display an abbreviation of the input units.
   *
   * @internal
   */
  accessor suffix: string | ((ctx: TooltipFieldContext) => string | null | undefined) | null | undefined;
  /**
   * A string or a function which returns a string to be displayed as the title of the field.
   *
   * @internal
   */
  accessor title: string | ((ctx: TooltipFieldContext) => string);
  /**
   * If true, the field will be unlocked when a vertex is placed.
   *
   * @default true
   * @internal
   */
  accessor unlockOnVertexPlacement: boolean;
  /**
   * Whether the field is visible.
   *
   * @default true
   * @internal
   */
  accessor visible: boolean;
}