import { __rest } from "tslib";
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
import React, { useRef, useState, useEffect, forwardRef, useImperativeHandle, useMemo, useContext } from 'react';
import { Clear, QuestionO } from '@react-vant/icons';
import clsx from 'clsx';
import Cell from '../cell';
import Dialog from '../dialog';
import { isDef, addUnit, formatNumber, isObject, preventDefault, resetScroll } from '../utils';
import ConfigProviderContext from '../config-provider/ConfigProviderContext';
import { COMPONENT_TYPE_KEY } from '../utils/constant';
const ICON_SIZE = '16px';
const Field = forwardRef((props, ref) => {
  const {
    prefixCls,
    createNamespace
  } = useContext(ConfigProviderContext);
  const [bem] = createNamespace('field', prefixCls);
  const [inputFocus, setInputFocus] = useState(false);
  const fieldRef = useRef(null);
  const inputRef = useRef(null);
  useEffect(() => {
    if (props.getFieldRef) props.getFieldRef(fieldRef);
    if (props.getInputRef) props.getInputRef(inputRef);
  }, [props.getFieldRef, props.getInputRef]);

  const focus = () => {
    if (inputRef.current) {
      inputRef.current.focus();
    }
  };

  const blur = () => {
    if (inputRef.current) {
      inputRef.current.blur();
    }
  };

  useImperativeHandle(ref, () => ({
    focus,
    blur
  }));

  const getProp = key => {
    if (isDef(props[key])) {
      return props[key];
    }

    return null;
  };

  const getModelValue = () => {
    var _a;

    return String((_a = props.value) !== null && _a !== void 0 ? _a : '');
  };

  const showClear = useMemo(() => {
    const readonly = getProp('readonly');

    if (props.clearable && !readonly) {
      const hasValue = getModelValue() !== '';
      const trigger = props.clearTrigger === 'always' || props.clearTrigger === 'focus' && inputFocus;
      return hasValue && trigger;
    }

    return false;
  }, [props.value, props.clearTrigger, inputFocus]);

  const labelStyle = () => {
    const labelW = getProp('labelWidth');

    if (labelW) {
      return {
        width: addUnit(labelW)
      };
    }

    return {};
  };

  const adjustSize = () => {
    const input = inputRef.current;

    if (!(props.type === 'textarea' && props.autosize) || !input) {
      return;
    }

    input.style.height = 'auto';
    let height = input.scrollHeight;

    if (isObject(props.autosize)) {
      const {
        maxHeight,
        minHeight
      } = props.autosize;

      if (maxHeight) {
        height = Math.min(height, maxHeight);
      }

      if (minHeight) {
        height = Math.max(height, minHeight);
      }
    }

    if (height) {
      input.style.height = `${height}px`;
    }
  };

  useEffect(() => {
    adjustSize();
  }, [props.value]);

  const formatValue = (inputValue, trigger = 'onChange') => {
    const {
      formatTrigger,
      formatter
    } = props;

    if (formatter && trigger === formatTrigger) {
      return formatter(inputValue);
    }

    return inputValue;
  };

  const renderInput = () => {
    const {
      type,
      error,
      name,
      rows,
      value,
      placeholder,
      disabled,
      readonly
    } = props;
    const controlClass = bem('control', [getProp('inputAlign'), {
      error,
      custom: !!props.children,
      'min-height': props.type === 'textarea' && !props.autosize
    }]);

    if (props.children) {
      return _jsx("div", Object.assign({
        className: clsx(controlClass)
      }, {
        children: props.children
      }));
    }

    const handleChange = e => {
      var _a;

      const {
        maxlength,
        onChange
      } = props;
      const inputValue = (_a = e === null || e === void 0 ? void 0 : e.currentTarget) === null || _a === void 0 ? void 0 : _a.value;
      let finalValue = inputValue;

      if (isDef(maxlength) && finalValue.length > +maxlength) {
        finalValue = finalValue.slice(0, maxlength);
      }

      if (type === 'number' || type === 'digit') {
        const isNumber = type === 'number';
        finalValue = formatNumber(finalValue, isNumber, isNumber);
      }

      finalValue = formatValue(finalValue, 'onChange'); // if (inputRef.value && inputValue !== inputRef.value.value) {
      //   inputRef.value.value = inputValue;
      // }

      if (onChange && typeof onChange === 'function') {
        onChange(finalValue);
      }
    };

    const handleFocus = e => {
      const {
        onFocus
      } = props;
      setInputFocus(true);

      if (onFocus && typeof onFocus === 'function') {
        onFocus(e);
      } // readonly not work in legacy mobile safari


      if (readonly) {
        blur();
      }
    };

    const handleBulr = e => {
      const {
        onBlur
      } = props;
      setInputFocus(false);

      if (onBlur && typeof onBlur === 'function') {
        onBlur(e);
      }

      resetScroll();
    };

    const handleKeypress = e => {
      const {
        onKeypress
      } = props;

      if (e.key === 'Enter' || +e.charCode === 13) {
        if (props.type !== 'textarea') {
          preventDefault(e);
        } // trigger blur after click keyboard search button


        if (props.type === 'search') {
          blur();
        }
      }

      if (onKeypress && typeof onKeypress === 'function') {
        onKeypress(e);
      }
    };

    if (type === 'textarea') {
      return _jsx("textarea", {
        ref: inputRef,
        name: name,
        rows: rows,
        className: clsx(controlClass),
        value: value,
        disabled: disabled,
        readOnly: readonly,
        placeholder: placeholder || '',
        onBlur: handleBulr,
        onFocus: handleFocus,
        onChange: handleChange,
        onKeyPress: handleKeypress
      });
    }

    let inputType = type;
    let inputMode; // type="number" is weired in iOS, and can't prevent dot in Android
    // so use inputmode to set keyboard in mordern browers

    if (type === 'number') {
      inputType = 'text';
      inputMode = 'decimal';
    }

    if (type === 'digit') {
      inputType = 'tel';
      inputMode = 'numeric';
    }

    return _jsx("input", {
      value: value,
      type: inputType,
      inputMode: inputMode,
      ref: inputRef,
      name: name,
      className: clsx(controlClass),
      disabled: disabled,
      readOnly: readonly,
      placeholder: placeholder || '',
      onBlur: handleBulr,
      onFocus: handleFocus,
      onChange: handleChange,
      onKeyPress: handleKeypress
    });
  };

  const renderLeftIcon = () => {
    const {
      leftIcon,
      onClickLeftIcon
    } = props;
    if (!leftIcon) return null;
    return _jsx("div", Object.assign({
      className: clsx(bem('left-icon')),
      onClick: onClickLeftIcon
    }, {
      children: leftIcon
    }));
  };

  const renderRightIcon = () => {
    const {
      rightIcon,
      onClickRightIcon
    } = props;
    if (!rightIcon) return null;
    return _jsx("div", Object.assign({
      className: clsx(bem('right-icon')),
      onClick: onClickRightIcon
    }, {
      children: rightIcon
    }));
  };

  const renderWordLimit = () => {
    const {
      value,
      showWordLimit,
      maxlength
    } = props;

    if (showWordLimit && maxlength) {
      const count = (value ? `${value}` : '').length;
      return _jsxs("div", Object.assign({
        className: clsx(bem('word-limit'))
      }, {
        children: [_jsx("span", Object.assign({
          className: clsx(bem('word-num'))
        }, {
          children: count
        })), "/", maxlength]
      }));
    }

    return null;
  };

  const renderMessage = () => {
    const message = props.errorMessage;

    if (message) {
      const errorMessageAlign = getProp('errorMessageAlign');
      return _jsx("div", Object.assign({
        className: clsx(bem('error-message', errorMessageAlign))
      }, {
        children: message
      }));
    }

    return null;
  };

  const renderIntro = () => {
    if (props.intro) {
      return _jsx("div", Object.assign({
        className: clsx(bem('intro', getProp('inputAlign')))
      }, {
        children: props.intro
      }));
    }

    return null;
  };

  const renderTooltip = () => {
    const {
      tooltip
    } = props;

    if (tooltip) {
      let icon = _jsx(QuestionO, {});

      let dialogProps = {
        message: tooltip
      };

      if (!(React.isValidElement(tooltip) || typeof tooltip === 'string')) {
        const _a = tooltip,
              {
          icon: customIcon
        } = _a,
              customDialogProps = __rest(_a, ["icon"]);

        icon = customIcon || icon;
        dialogProps = customDialogProps;
      }

      return _jsx("div", Object.assign({
        className: clsx(bem('tooltip')),
        onClick: () => Dialog.show(dialogProps)
      }, {
        children: icon
      }));
    }

    return null;
  };

  const renderLabel = () => {
    const {
      label,
      colon
    } = props;

    if (label) {
      return _jsxs(_Fragment, {
        children: [label, colon && ':', renderTooltip()]
      });
    }

    return null;
  };

  const handleClear = e => {
    const {
      onClear,
      onChange
    } = props;
    inputRef.current.value = '';

    if (onChange && typeof onChange === 'function') {
      onChange('');
    }

    if (onClear && typeof onClear === 'function') {
      onClear(e);
    }
  };

  const {
    type,
    size,
    center,
    border,
    isLink,
    required,
    clickable,
    labelAlign,
    className,
    labelClass,
    valueClass,
    arrowDirection,
    autosize,
    disabled,
    button,
    titleStyle,
    error
  } = props;
  return _jsxs(Cell, Object.assign({
    title: renderLabel(),
    size: size,
    icon: renderLeftIcon(),
    center: center,
    border: border,
    isLink: isLink,
    required: required,
    clickable: clickable,
    extra: props.extra,
    titleStyle: Object.assign(Object.assign({}, labelStyle()), titleStyle),
    valueClass: clsx(bem('value'), valueClass),
    titleClass: clsx(bem('label', labelAlign), labelClass),
    arrowDirection: arrowDirection,
    onClick: props.onClick,
    style: props.style,
    className: clsx(bem({
      error,
      disabled,
      [`label-${labelAlign}`]: labelAlign,
      'min-height': type === 'textarea' && !autosize
    }), className)
  }, {
    children: [_jsxs("div", Object.assign({
      className: clsx(bem('body'))
    }, {
      children: [_jsx("div", Object.assign({
        className: clsx(bem('control-wrapper')),
        onClick: props.onClickInput
      }, {
        children: renderInput()
      })), showClear && React.cloneElement(props.clearIcon, {
        className: clsx(bem('clear')),
        onTouchStart: handleClear,
        size: ICON_SIZE
      }), renderRightIcon(), button && _jsx("div", Object.assign({
        className: clsx(bem('button'))
      }, {
        children: button
      }))]
    })), renderWordLimit(), renderMessage(), renderIntro()]
  }));
});
Field.defaultProps = {
  clearIcon: _jsx(Clear, {}),
  clearTrigger: 'focus',
  formatTrigger: 'onChange'
};
export const FIELD_KEY = Symbol('field');
const FieldNamespace = Object.assign(Field, {
  [COMPONENT_TYPE_KEY]: FIELD_KEY
});
export default FieldNamespace;