import React, { useState, useEffect, cloneElement } from 'react';
import classNames from 'classnames';
// eslint-disable-next-line you-dont-need-lodash-underscore/get
import get from 'lodash-es/get';
import { faCircleNotch } from '@fortawesome/free-solid-svg-icons/faCircleNotch';
import { faCheck } from '@fortawesome/free-solid-svg-icons/faCheck';
import { faXmark } from '@fortawesome/free-solid-svg-icons/faXmark';
import { faRedoAlt } from '@fortawesome/free-solid-svg-icons/faRedoAlt';
import { FontAwesomeIcon } from '../font-awesome-icon';
import { Button, ACCENT_TYPES, BUTTON_TYPES, BUTTON_SIZES } from '../button';
import { Tooltip } from '../tooltip';
import { FormFieldLabel } from './form-field-label';
import PasswordToggleButton from './password-toggle-button';
import ValidityMessages from './validity-messages';
import { isPassword, getValidationMessagesIds } from './utilities';
import { useTranslation } from '../hooks/use-translation';
import { MESSAGE_DISPLAY_LOCATION, ICON_POSITION, useDefaultValidationValues, VALIDATION_RULE_TYPES } from './constants';
import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
export let HELPER_TEXT_POSITION = /*#__PURE__*/function (HELPER_TEXT_POSITION) {
  HELPER_TEXT_POSITION["TOP"] = "top";
  HELPER_TEXT_POSITION["BOTTOM"] = "bottom";
  return HELPER_TEXT_POSITION;
}({});
export default function FormField({
  id,
  value = '',
  helperText = '',
  helperTextPosition = HELPER_TEXT_POSITION.TOP,
  label = '',
  readOnly,
  className = '',
  wrapperClass = '',
  isDisabled = false,
  isOptional = false,
  isHighlighted = false,
  disabledInfo = '',
  autoFocus = false,
  validity,
  asyncValidation = {
    isValidating: false,
    isRetryShown: false,
    onRetry: () => {}
  },
  touched = false,
  leftIcon = null,
  rightIcon = null,
  iconTooltipText = '',
  labelIcon = null,
  labelIconTestId,
  labelIconTooltipText,
  fieldClass,
  placeholder = '',
  required = false,
  onChange = () => {},
  onBlur = () => {},
  onSubmit = () => {},
  onCancel = () => {},
  submitAriaLabel,
  cancelAriaLabel,
  retryAriaLabel,
  clearAriaLabel,
  onKeyDown = () => {},
  onFocus = () => {},
  onWheel = () => {},
  onClear,
  children,
  fieldTestId = 'dr-field',
  validationTestId = 'dr-field-validation-result',
  disabledInfoTestId = 'dr-field-disabled-info',
  labelTestId,
  normalize = ({
    nextValue
  }) => nextValue,
  shouldDisplayControls,
  showPasswordToggle = true,
  type,
  spellCheck,
  isHorizontalLayout,
  disableApplyButton,
  passwordToggleButtonTexts: passwordToggleButtonTextsParams,
  validationValues: validationValuesParams,
  optionalLabelText,
  ...attrs
}) {
  const {
    t
  } = useTranslation();
  const defaultValidationValues = useDefaultValidationValues();
  const validationValues = validationValuesParams ?? defaultValidationValues;
  const passwordToggleButtonTexts = passwordToggleButtonTextsParams ?? {
    show: t('Show password'),
    hide: t('Hide password')
  };
  const [localValue, setLocalValue] = useState(value);
  const [isFocused, setFocus] = useState(autoFocus);
  const [isTouched, setTouch] = useState(touched);
  const [currentType, setCurrentType] = useState(type);
  useEffect(() => {
    setLocalValue(normalize({
      nextValue: value,
      prevValue: ''
    }));
  }, [value]);
  useEffect(() => setTouch(touched), [touched]);
  useEffect(
  // disabled elements might not receive onBlur event
  // https://github.com/facebook/react/issues/9142
  () => {
    if (isDisabled && isFocused) {
      setFocus(false);
    }
  }, [isDisabled, isFocused]);
  const validityType = get(validity, 'type');
  let validityValue;
  if (validityType) {
    validityValue = get(validity, 'value', validationValues[validityType]);
  }
  const validityDisplayLocation = get(validity, 'displayLocation', MESSAGE_DISPLAY_LOCATION.INLINE);
  const isPasswordField = isPassword(type);
  const showValidationResult = Boolean(validityValue) && isTouched;
  const icon = getIcon();
  const iconPosition = getIconPosition();
  const isValidationFailed = validityType === VALIDATION_RULE_TYPES.ERROR;
  const isValidationSucceeded = validityType === VALIDATION_RULE_TYPES.SUCCESS;
  const isValidationWarned = validityType === VALIDATION_RULE_TYPES.WARNING;
  const rootClasses = classNames('dr-form-field', className, {
    [`with-${iconPosition}-icon`]: iconPosition,
    'dr-form-field-validation-error': showValidationResult && isValidationFailed,
    'dr-form-field-validation-warning': showValidationResult && isValidationWarned,
    'dr-form-field-validation-success': showValidationResult && isValidationSucceeded,
    focused: isFocused,
    disabled: isDisabled,
    highlighted: isHighlighted,
    required,
    'horizontal-layout': isHorizontalLayout
  });
  function handleChange(e) {
    const normalizedValue = normalize({
      nextValue: e.target.value,
      prevValue: localValue
    });
    setLocalValue(normalizedValue);
    onChange(e, {
      normalizedValue
    });
  }
  function handleFocus(e) {
    setFocus(true);
    onFocus(e);
  }
  function handleBlur(e) {
    setFocus(false);
    setTouch(true);
    onBlur(e);
  }
  function getIconPosition() {
    if (isPasswordField || asyncValidation.isRetryShown) {
      return ICON_POSITION.CENTER_RIGHT;
    }
    if (asyncValidation.isValidating || rightIcon) {
      return ICON_POSITION.RIGHT;
    }
    if (leftIcon) {
      return ICON_POSITION.LEFT;
    }
  }
  function getIcon() {
    if (asyncValidation.isRetryShown) {
      return;
    }
    if (asyncValidation.isValidating) {
      return faCircleNotch;
    }
    return leftIcon || rightIcon;
  }
  const validationMessagesIds = showValidationResult ? getValidationMessagesIds({
    validity,
    validationValues,
    fieldId: id
  }) : '';
  const ariaDescribedByIds = `${validationMessagesIds} ${attrs['aria-describedby'] ?? ''}`.trim();
  const ariaAttrs = {
    'aria-required': required,
    ...(ariaDescribedByIds && {
      'aria-describedby': ariaDescribedByIds
    }),
    ...(showValidationResult && {
      'aria-invalid': isValidationFailed
    })
  };
  const props = {
    id,
    disabled: isDisabled,
    autoFocus,
    placeholder,
    spellCheck: JSON.stringify(spellCheck),
    onKeyDown,
    type: currentType,
    value: localValue,
    onChange: handleChange,
    onBlur: handleBlur,
    onFocus: handleFocus,
    onWheel,
    readOnly,
    className: classNames(fieldClass, {
      'dr-form-field-control-validated': showValidationResult
    }),
    'test-id': fieldTestId,
    ...attrs,
    ...ariaAttrs
  };
  return /*#__PURE__*/_jsxs("div", {
    className: rootClasses,
    "test-id": "dr-form-field-root",
    children: [label && /*#__PURE__*/_jsx(FormFieldLabel, {
      label: label,
      id: id,
      labelTestId: labelTestId,
      labelIcon: labelIcon,
      labelIconTestId: labelIconTestId,
      labelIconTooltipText: labelIconTooltipText,
      isOptional: isOptional,
      isDisabled: isDisabled,
      isReadOnly: readOnly,
      optionalLabelText: optionalLabelText ?? t('Optional')
    }), helperText && helperTextPosition === HELPER_TEXT_POSITION.TOP && /*#__PURE__*/_jsx("div", {
      className: classNames('dr-form-field-text', {
        disabled: isDisabled
      }),
      children: helperText
    }), /*#__PURE__*/_jsxs("div", {
      className: classNames(wrapperClass, 'dr-form-field-wrapper'),
      children: [!isPasswordField && icon && /*#__PURE__*/_jsx(Tooltip, {
        content: iconTooltipText,
        placement: "top",
        children: /*#__PURE__*/_jsx(FontAwesomeIcon, {
          "test-id": "form-field-icon",
          icon: icon,
          className: classNames('dr-form-field-icon', {
            disabled: isDisabled
          }),
          spin: asyncValidation.isValidating
        })
      }), children ? /*#__PURE__*/cloneElement(children, props) : null, shouldDisplayControls && /*#__PURE__*/_jsxs(_Fragment, {
        children: [/*#__PURE__*/_jsx("button", {
          "test-id": "cancel-button",
          className: "button editable-icon cancel",
          onClick: onCancel,
          type: BUTTON_TYPES.BUTTON,
          "aria-label": cancelAriaLabel ?? t('Cancel'),
          children: /*#__PURE__*/_jsx(FontAwesomeIcon, {
            icon: faXmark
          })
        }), /*#__PURE__*/_jsx("button", {
          "test-id": "apply-button",
          className: classNames('button editable-icon apply', {
            disabled: disableApplyButton
          }),
          onClick: onSubmit,
          type: BUTTON_TYPES.BUTTON,
          disabled: disableApplyButton,
          "aria-label": submitAriaLabel ?? t('Submit'),
          children: /*#__PURE__*/_jsx(FontAwesomeIcon, {
            icon: faCheck
          })
        })]
      }), isPasswordField && showPasswordToggle && /*#__PURE__*/_jsx(PasswordToggleButton, {
        isDisabled: isDisabled,
        onClick: setCurrentType,
        fieldType: currentType,
        passwordToggleButtonTexts: passwordToggleButtonTexts
      }), asyncValidation.isRetryShown && /*#__PURE__*/_jsx(Button, {
        accentType: ACCENT_TYPES.ROUND_ICON,
        className: "toggle-password-button",
        onClick: asyncValidation.onRetry,
        testId: "retry-async-validation",
        size: BUTTON_SIZES.XS,
        "aria-label": retryAriaLabel ?? t('Retry'),
        children: /*#__PURE__*/_jsx(FontAwesomeIcon, {
          icon: faRedoAlt
        })
      }), !!onClear && /*#__PURE__*/_jsx(Button, {
        accentType: ACCENT_TYPES.ROUND_ICON,
        className: "toggle-password-button",
        onClick: onClear,
        testId: "clear-button",
        size: BUTTON_SIZES.XS,
        "aria-label": clearAriaLabel ?? t('Clear'),
        children: /*#__PURE__*/_jsx(FontAwesomeIcon, {
          icon: faXmark
        })
      })]
    }), helperText && helperTextPosition === HELPER_TEXT_POSITION.BOTTOM && /*#__PURE__*/_jsx("div", {
      className: classNames('dr-form-field-text helper-text-bottom', {
        disabled: isDisabled
      }),
      children: helperText
    }), isDisabled && /*#__PURE__*/_jsx(ValidityMessages, {
      validity: {
        type: VALIDATION_RULE_TYPES.INFO,
        value: disabledInfo
      },
      validationTestId: disabledInfoTestId,
      validationValues: validationValues
    }), showValidationResult && validityDisplayLocation === MESSAGE_DISPLAY_LOCATION.INLINE && /*#__PURE__*/_jsx(ValidityMessages, {
      validity: validity,
      validationTestId: validationTestId,
      validationValues: validationValues,
      fieldId: id
    })]
  });
}