import { Fragment as _Fragment } from "vue";
import _objectSpread from "@babel/runtime/helpers/esm/objectSpread2";
import { createVNode as _createVNode } from "vue";
import _extends from "@babel/runtime/helpers/esm/extends";
import { Fragment, computed, defineComponent, ref, watchEffect } from 'vue';
import inputProps from '../inputProps';
import { FormItemInputContext } from '../../form/FormItemContext';
import useConfigInject from '../../config-provider/hooks/useConfigInject';
import classNames from '../../_util/classNames';
import useStyle from '../style/otp';
import OTPInput from './OTPInput';
import { getMergedStatus } from '../../_util/statusUtils';
import warning from '../../_util/warning';
export default defineComponent({
  compatConfig: {
    MODE: 3
  },
  name: 'AOTP',
  inheritAttrs: false,
  slots: Object,
  props: _extends(_extends({}, inputProps()), {
    length: {
      type: Number,
      default: 6
    },
    onChange: {
      type: Function,
      default: undefined
    },
    onInput: {
      type: Function,
      default: undefined
    },
    formatter: {
      type: Function,
      default: undefined
    },
    defaultValue: {
      type: String,
      default: undefined
    },
    mask: {
      type: [String, Boolean],
      default: false
    },
    status: {
      type: String,
      default: undefined
    },
    separator: {
      type: [Function, Object],
      default: undefined
    }
  }),
  setup(props, {
    attrs,
    slots
  }) {
    const {
      prefixCls,
      direction,
      size
    } = useConfigInject('otp', props);
    // Style
    const [wrapSSR, hashId] = useStyle(prefixCls);
    // ==================== Provider =========================
    const formItemInputContext = FormItemInputContext.useInject();
    const mergedStatus = computed(() => getMergedStatus(formItemInputContext.status, props.status));
    const refs = ref([]);
    const strToArr = str => (str || '').split('');
    // keep reactive
    const internalFormatter = txt => props.formatter ? props.formatter(txt) : txt;
    const valueCells = ref(strToArr(internalFormatter(props.defaultValue || '')));
    watchEffect(() => {
      if (typeof props.value !== 'undefined' && props.value !== null) {
        valueCells.value = strToArr(String(props.value));
      }
    });
    const patchValue = (index, txt) => {
      let nextCells = valueCells.value.slice();
      for (let i = 0; i < index; i += 1) {
        if (!nextCells[i]) {
          nextCells[i] = '';
        }
      }
      if (txt.length <= 1) {
        nextCells[index] = txt;
      } else {
        nextCells = nextCells.slice(0, index).concat(strToArr(txt));
      }
      nextCells = nextCells.slice(0, props.length);
      for (let i = nextCells.length - 1; i >= 0; i -= 1) {
        if (nextCells[i]) {
          break;
        }
        nextCells.pop();
      }
      const formattedValue = internalFormatter(nextCells.map(c => c || ' ').join(''));
      nextCells = strToArr(formattedValue).map((c, i) => {
        if (c === ' ' && !nextCells[i]) {
          return nextCells[i];
        }
        return c;
      });
      return nextCells;
    };
    // ======================= Change handlers =================
    const onInputActiveChange = nextIndex => {
      var _a;
      (_a = refs.value[nextIndex]) === null || _a === void 0 ? void 0 : _a.focus();
    };
    const onInputChange = (index, value) => {
      var _a;
      const nextValueCells = patchValue(index, value);
      const nextIndex = Math.min(index + value.length, props.length);
      if (nextIndex !== index) {
        (_a = refs.value[nextIndex]) === null || _a === void 0 ? void 0 : _a.focus();
      }
      if (props.onInput) {
        props.onInput(nextValueCells);
      }
      if (props.onChange && nextValueCells.length === props.length && nextValueCells.every(v => v) && nextValueCells.some((v, i) => v !== valueCells.value[i])) {
        props.onChange(nextValueCells.join(''));
      }
      valueCells.value = nextValueCells.slice();
    };
    // ======================== Focus ========================
    const onInputFocus = (e, index) => {
      var _a, _b, _c, _d, _e, _f;
      for (let i = 0; i < index; i++) {
        if (!((_d = (_c = (_b = (_a = refs.value[i]) === null || _a === void 0 ? void 0 : _a.inputRef) === null || _b === void 0 ? void 0 : _b.input) === null || _c === void 0 ? void 0 : _c.input) === null || _d === void 0 ? void 0 : _d.value)) {
          (_e = refs.value[i]) === null || _e === void 0 ? void 0 : _e.focus();
        }
      }
      (_f = props.onFocus) === null || _f === void 0 ? void 0 : _f.call(props, e);
    };
    return () => {
      const cls = classNames(prefixCls.value, {
        [`${prefixCls.value}-sm`]: size.value === 'small',
        [`${prefixCls.value}-lg`]: size.value === 'large',
        [`${prefixCls.value}-rtl`]: direction.value === 'rtl'
      }, attrs.class, hashId.value);
      const {
        length,
        autofocus,
        disabled,
        mask,
        variant,
        separator = slots.separator
      } = props;
      const inputShardProps = {
        disabled,
        mask,
        variant,
        prefixCls: prefixCls.value
      };
      if (process.env.NODE_ENV !== 'production') {
        warning(!(typeof mask === 'string' && mask.length > 1), 'Input.OTP', '`mask` prop should be a single character.');
      }
      return wrapSSR(_createVNode("div", {
        "class": cls
      }, [Array.from({
        length
      }).map((_, index) => {
        const key = `opt-${index}`;
        const singleValue = valueCells.value[index];
        const separatorNode = typeof separator === 'function' ? separator({
          index
        }) : separator;
        return _createVNode(_Fragment, {
          "key": key
        }, [_createVNode(OTPInput, _objectSpread({
          "ref": ref => refs.value[index] = ref,
          "key": key,
          "index": index,
          "class": `${prefixCls.value}-input`,
          "value": singleValue,
          "htmlSize": 1,
          "onChange": onInputChange,
          "status": mergedStatus.value,
          "onActiveChange": onInputActiveChange,
          "autofocus": index === 0 && autofocus,
          "onFocus": e => onInputFocus(e, index)
        }, inputShardProps), null), index < length - 1 && separator && _createVNode("span", {
          "class": `${prefixCls.value}-separator`
        }, [separatorNode])]);
      })]));
    };
  }
});