import type Element from "./Element.js";
import type CodedValueDomain from "../../layers/support/CodedValueDomain.js";
import type RangeDomain from "../../layers/support/RangeDomain.js";
import type { ElementProperties } from "./Element.js";
import type { Input } from "./inputs.js";
import type { RangeDomainProperties } from "../../layers/support/RangeDomain.js";
import type { CodedValueDomainProperties } from "../../layers/support/CodedValueDomain.js";
import type { TimePickerInputProperties } from "./inputs/TimePickerInput.js";
import type { TextBoxInputProperties } from "./inputs/TextBoxInput.js";
import type { TextAreaInputProperties } from "./inputs/TextAreaInput.js";
import type { SwitchInputProperties } from "./inputs/SwitchInput.js";
import type { RadioButtonsInputProperties } from "./inputs/RadioButtonsInput.js";
import type { DateTimePickerInputProperties } from "./inputs/DateTimePickerInput.js";
import type { DateTimeOffsetPickerInputProperties } from "./inputs/DateTimeOffsetPickerInput.js";
import type { DatePickerInputProperties } from "./inputs/DatePickerInput.js";
import type { ComboBoxInputProperties } from "./inputs/ComboBoxInput.js";
import type { BarcodeScannerInputProperties } from "./inputs/BarcodeScannerInput.js";

export interface FieldElementProperties extends ElementProperties, Partial<Pick<FieldElement, "editableExpression" | "fieldName" | "hint" | "requiredExpression" | "valueExpression">> {
  /**
   * The [coded value domain](https://developers.arcgis.com/javascript/latest/references/core/layers/support/CodedValueDomain/) or
   * [range domain](https://developers.arcgis.com/javascript/latest/references/core/layers/support/RangeDomain/) of the field.
   */
  domain?: (CodedValueDomainProperties & { type: "coded-value" }) | (RangeDomainProperties & { type: "range" }) | null;
  /** The input to use for the element. The client application is responsible for defining the default user interface. */
  input?: ((BarcodeScannerInputProperties & { type: "barcode-scanner" }) | (ComboBoxInputProperties & { type: "combo-box" }) | (DatePickerInputProperties & { type: "date-picker" }) | (DateTimeOffsetPickerInputProperties & { type: "datetimeoffset-picker" }) | (DateTimePickerInputProperties & { type: "datetime-picker" }) | (RadioButtonsInputProperties & { type: "radio-buttons" }) | (SwitchInputProperties & { type: "switch" }) | (TextAreaInputProperties & { type: "text-area" }) | (TextBoxInputProperties & { type: "text-box" }) | (TimePickerInputProperties & { type: "time-picker" })) | null;
}

/**
 * A `FieldElement` form element defines how a feature layer's [Field](https://developers.arcgis.com/javascript/latest/references/core/layers/support/Field/)
 * participates in the [FeatureForm](https://developers.arcgis.com/javascript/latest/references/core/widgets/FeatureForm/). Use this approach to set field configurations within a
 * [feature form](https://developers.arcgis.com/javascript/latest/references/core/widgets/FeatureForm/#formTemplate)
 * or [feature layer](https://developers.arcgis.com/javascript/latest/references/core/layers/FeatureLayer/#formTemplate) `formTemplate`.
 *
 * ![form template field elements](https://developers.arcgis.com/javascript/latest/assets/img/apiref/widgets/formtemplate/field-elements-updated.png)
 *
 * @since 4.16
 * @see [FormTemplate](https://developers.arcgis.com/javascript/latest/references/core/form/FormTemplate/)
 * @see [FeatureForm](https://developers.arcgis.com/javascript/latest/references/core/widgets/FeatureForm/)
 * @see [GroupElement](https://developers.arcgis.com/javascript/latest/references/core/form/elements/GroupElement/)
 * @see [Field](https://developers.arcgis.com/javascript/latest/references/core/layers/support/Field/)
 * @see [Sample - Editor using calculated expressions](https://developers.arcgis.com/javascript/latest/sample-code/widgets-featureform-async)
 * @see [Sample - Update Feature Attributes](https://developers.arcgis.com/javascript/latest/sample-code/editing-groupedfeatureform/)
 * @see [Sample - Advanced Attribute Editing](https://developers.arcgis.com/javascript/latest/sample-code/editing-featureform-fieldvisibility/)
 * @example
 * // Create the field element
 * const fieldElement1 = new FieldElement({
 *   fieldName: "inspector",
 *   label: "Inspector name"
 * });
 *
 * const fieldElement2 = new FieldElement({
 *   fieldName: "inspdate",
 *   label: "Inspection date",
 *   description: "Date inspection was handled",
 *   input: { // autocastable to DatePickerInput
 *     type: "date-picker",
 *       min: "2010-01-15",
 *       max: "2030-01-15"
 *     }
 * });
 *
 * const fieldElement3 = new FieldElement({
 *   fieldName: "placename",
 *   label: "Business name",
 *   editableExpression: "editing-disabled"
 * });
 *
 * const fieldElement4 = new FieldElement({
 *   fieldName: "floodinsur",
 *   label: "Flood insurance",
 *   input: { // autocastable to RadioButtonsInput
 *     type: "radio-buttons",
 *     noValueOptionLabel: "Not applicable",
 *     showNoValueOption: true
 *   }
 * });
 *
 * // Next pass in any elements to the FormTemplate
 * const formTemplate = new FormTemplate({
 *   title: "Inspector report",
 *   description: "Enter all relevant information below",
 *   expressionInfos: [{
 *     name: "editing-disabled",
 *     expression: "false",
 *     returnType: "boolean"
 *   }],
 *   elements: [fieldElement1, fieldElement2, fieldElement3, fieldElement4] // Add all elements to the template
 * });
 */
export default class FieldElement extends Element {
  constructor(properties?: FieldElementProperties);
  /**
   * The [coded value domain](https://developers.arcgis.com/javascript/latest/references/core/layers/support/CodedValueDomain/) or
   * [range domain](https://developers.arcgis.com/javascript/latest/references/core/layers/support/RangeDomain/) of the field.
   */
  get domain(): CodedValueDomain | RangeDomain | null | undefined;
  set domain(value: (CodedValueDomainProperties & { type: "coded-value" }) | (RangeDomainProperties & { type: "range" }) | null | undefined);
  /**
   * A reference to the [ExpressionInfo.name](https://developers.arcgis.com/javascript/latest/references/core/form/ExpressionInfo/#name) of an
   * [Arcade](https://developers.arcgis.com/javascript/latest/arcade/) expression defined in the
   * [FormTemplate.expressionInfos](https://developers.arcgis.com/javascript/latest/references/core/form/FormTemplate/#expressionInfos) of the FormTemplate.
   *
   * When this expression evaluates to `true`, it is possible to edit the field value, and vice-versa if `false`. If the referenced field on the feature service
   * is not editable, the editable expression is ignored and the element is not editable.
   *
   * > [!WARNING]
   * >
   * > The expression must follow the specification
   * > defined in the [Form Constraint Profile](https://developers.arcgis.com/javascript/latest/arcade/#constraint). Expressions
   * > may reference field values using the `$feature` global input and must return either `true` or `false`.
   * > It is required to set the [FeatureForm.map](https://developers.arcgis.com/javascript/latest/references/core/widgets/FeatureForm/#map) property when instantiating a [FeatureForm](https://developers.arcgis.com/javascript/latest/references/core/widgets/FeatureForm/) widget and using expressions that make use of the `$map` variable.
   * > Editing must be disabled if setting a field element's [valueExpression](https://developers.arcgis.com/javascript/latest/references/core/form/elements/FieldElement/#valueExpression).
   * > The referenced expression must be defined in the form template's [FormTemplate.expressionInfos](https://developers.arcgis.com/javascript/latest/references/core/form/FormTemplate/#expressionInfos).
   * > It cannot be set inline within the element object.
   *
   * @since 4.23
   * @see [Sample - Advanced Attribute Editing](https://developers.arcgis.com/javascript/latest/sample-code/editing-featureform-fieldvisibility/)
   * @see [Form Constraint Arcade Profile](https://developers.arcgis.com/javascript/latest/arcade/#constraint)
   */
  accessor editableExpression: string | null | undefined;
  /** The field name as defined by the feature layer. Set this property to indicate which field to edit. */
  accessor fieldName: string | null | undefined;
  /**
   * Contains a hint used to help editors while editing fields.
   * Set this as a temporary placeholder
   * for text/number inputs in either [TextAreaInput](https://developers.arcgis.com/javascript/latest/references/core/form/elements/inputs/TextAreaInput/) or
   * [TextBoxInput](https://developers.arcgis.com/javascript/latest/references/core/form/elements/inputs/TextBoxInput/).
   */
  accessor hint: string | null | undefined;
  /** The input to use for the element. The client application is responsible for defining the default user interface. */
  get input(): Input | null | undefined;
  set input(value: ((BarcodeScannerInputProperties & { type: "barcode-scanner" }) | (ComboBoxInputProperties & { type: "combo-box" }) | (DatePickerInputProperties & { type: "date-picker" }) | (DateTimeOffsetPickerInputProperties & { type: "datetimeoffset-picker" }) | (DateTimePickerInputProperties & { type: "datetime-picker" }) | (RadioButtonsInputProperties & { type: "radio-buttons" }) | (SwitchInputProperties & { type: "switch" }) | (TextAreaInputProperties & { type: "text-area" }) | (TextBoxInputProperties & { type: "text-box" }) | (TimePickerInputProperties & { type: "time-picker" })) | null | undefined);
  /**
   * A reference to the [ExpressionInfo.name](https://developers.arcgis.com/javascript/latest/references/core/form/ExpressionInfo/#name) of an
   * [Arcade](https://developers.arcgis.com/javascript/latest/arcade/) expression defined in the
   * [FormTemplate.expressionInfos](https://developers.arcgis.com/javascript/latest/references/core/form/FormTemplate/#expressionInfos) of the [FormTemplate](https://developers.arcgis.com/javascript/latest/references/core/form/FormTemplate/). An expression that evaluates to `true` results in the field element requiring the end
   * user to provide a value for [fieldName](https://developers.arcgis.com/javascript/latest/references/core/form/elements/FieldElement/#fieldName) for the feature to be created or edited.
   * If the expression evaluates to `false`, the end user is not required to provide a value to
   * the element.
   *
   * If the referenced [fieldName](https://developers.arcgis.com/javascript/latest/references/core/form/elements/FieldElement/#fieldName) is non-nullable,
   * the `requiredExpression` is ignored and the element
   * is always required.
   *
   * > [!WARNING]
   * >
   * > The expression must follow the specification
   * > defined in the [Form Constraint Profile](https://developers.arcgis.com/javascript/latest/arcade/#constraint). Expressions
   * > may reference field values using the `$feature` global input and must return either `true` or `false`.
   * > It is required to set the [FeatureForm.map](https://developers.arcgis.com/javascript/latest/references/core/widgets/FeatureForm/#map) property when instantiating a [FeatureForm](https://developers.arcgis.com/javascript/latest/references/core/widgets/FeatureForm/) widget and using expressions that make use of the `$map` variable.
   * > The referenced expression must be defined in the form template's [FormTemplate.expressionInfos](https://developers.arcgis.com/javascript/latest/references/core/form/FormTemplate/#expressionInfos). It cannot be set inline to this property.
   * > [Field](https://developers.arcgis.com/javascript/latest/references/core/form/elements/FieldElement/) and [Group](https://developers.arcgis.com/javascript/latest/references/core/form/elements/GroupElement/) elements must be visible if the field or one of the grouped fields is required.
   *
   * @see [Form Constraint Arcade Profile](https://developers.arcgis.com/javascript/latest/arcade/#constraint)
   * @example
   * // The diameter field requires a value to be created or edited
   * // if the inspectionStatus value is "Complete"
   * // if the status is not complete, then this field value is optional
   * const dbhFieldElement = new FieldElement({
   *   fieldName: "diameter",
   *   input: {
   *     type: "text-box"
   *   },
   *   requiredExpression: "tree-dbh",
   *   editableExpression: "editable"
   * });
   *
   * layer.formTemplate = new FormTemplate({
   *   elements: [ dbhFieldElement ],
   *   expressionInfos: [{
   *     expression: "$feature.inspectionStatus == 'Complete'",
   *     name: "tree-dbh",
   *     title: "Tree DBH",
   *     returnType: "boolean"
   *   }, {
   *     expression: "true",
   *     name: "editable",
   *     returnType: "boolean"
   *   }]
   * });
   * @example
   * // The field value will ALWAYS be required when editing with a form
   * const dbhFieldElement = new FieldElement({
   *   editable: true,
   *   fieldName: "diameter",
   *   input: {
   *     type: "text-box"
   *   },
   *   requiredExpression: "always-required",
   *   editableExpression: "editable"
   * });
   *
   * layer.formTemplate = new FormTemplate({
   *   elements: [ dbhFieldElement ],
   *   expressionInfos: [{
   *     // An expression that always returns true
   *     expression: "true",
   *     name: "always-required",
   *     returnType: "boolean"
   *   }, {
   *     expression: "true",
   *     name: "editable",
   *     returnType: "boolean"
   *   }]
   * });
   */
  accessor requiredExpression: string | null | undefined;
  /** Indicates the type of form [Element](https://developers.arcgis.com/javascript/latest/references/core/form/elements/Element/). */
  get type(): "field";
  /**
   * A reference to the [ExpressionInfo.name](https://developers.arcgis.com/javascript/latest/references/core/form/ExpressionInfo/#name) of an
   * [Arcade](https://developers.arcgis.com/javascript/latest/arcade/) expression defined in the
   * [FormTemplate.expressionInfos](https://developers.arcgis.com/javascript/latest/references/core/form/FormTemplate/#expressionInfos) of the [FormTemplate](https://developers.arcgis.com/javascript/latest/references/core/form/FormTemplate/).
   *
   * Once the expression evaluates, the form's field value updates to the expression's result.
   *
   * > [!WARNING]
   * >
   * > The expression must follow the specification
   * > defined in the [Form Calculation Profile](https://developers.arcgis.com/javascript/latest/arcade/#form-calculation). This expression references field values within an individual feature or in other layers and must return either a date, number, or string value.
   * > Editing must be disabled, which may be done via the [editableExpression](https://developers.arcgis.com/javascript/latest/references/core/form/elements/FieldElement/#editableExpression).
   * > The referenced expression must be defined in the form template's [FormTemplate.expressionInfos](https://developers.arcgis.com/javascript/latest/references/core/form/FormTemplate/#expressionInfos). It cannot be set inline within the element object.
   *
   * @since 4.23
   * @see [Sample - Editing with calculated field expressions](https://developers.arcgis.com/javascript/latest/sample-code/widgets-featureform-async/)
   * @see [Form Calculation Arcade Profile](https://developers.arcgis.com/javascript/latest/arcade/#form-calculation)
   * @example
   * // Calculates the diameter based on the circumference field
   * const dbhFieldElement = new FieldElement({
   *   fieldName: "diameter",
   *   input: {
   *     type: "text-box"
   *   },
   *   valueExpression: "tree-dbh",
   *   // element must not be editable to enable valueExpression
   *   editableExpression: "not-editable"
   * });
   *
   * layer.formTemplate = new FormTemplate({
   *   elements: [ dbhFieldElement ],
   *   expressionInfos: [{
   *     expression: "Round(DefaultValue($feature.circumference, 0) / PI, 1)",
   *     name: "tree-dbh",
   *     title: "Tree DBH",
   *     returnType: "boolean"
   *   }, {
   *     expression: "false",
   *     name: "not-editable",
   *     returnType: "boolean"
   *   }]
   * });
   */
  accessor valueExpression: string | null | undefined;
  /**
   * Creates a deep clone of the FieldElement class.
   *
   * @returns A deep clone of the FieldElement instance.
   */
  clone(): FieldElement;
}