import _defineProperty from '@babel/runtime/helpers/esm/defineProperty';
import { defineComponent, inject, computed, getCurrentInstance, ref, onBeforeUnmount, provide, nextTick, openBlock, createElementBlock, normalizeClass, normalizeStyle, renderSlot, createTextVNode, toDisplayString, createCommentVNode, createElementVNode, createVNode, Transition, withCtx } from 'vue';
import Schema from 'async-validator';
import { get, cloneDeep, isNil, isArray, set } from 'lodash-es';
import { pxfy } from '../_util/utils';
import getPrefixCls from '../_util/getPrefixCls';
import { FORM_ITEM_INJECTION_KEY } from '../_util/constants';
import { FORM_ITEM_NAME, provideKey, VALIDATE_STATUS, VALIDATE_MESSAGE_DEFAULT, FORM_LAYOUT, LABEL_POSITION, FORM_ITEM_ALIGN, RULE_TYPE_DEFAULT, TRIGGER_TYPE_DEFAULT } from './const';
import { wrapValidator } from './utils';
import { formItemProps } from './interface';

function ownKeys(e, r) { var t = Object.keys(e); if (Object.getOwnPropertySymbols) { var o = Object.getOwnPropertySymbols(e); r && (o = o.filter(function (r) { return Object.getOwnPropertyDescriptor(e, r).enumerable; })), t.push.apply(t, o); } return t; }
function _objectSpread(e) { for (var r = 1; r < arguments.length; r++) { var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? ownKeys(Object(t), !0).forEach(function (r) { _defineProperty(e, r, t[r]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : ownKeys(Object(t)).forEach(function (r) { Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r)); }); } return e; }
const prefixCls = getPrefixCls('form-item');
var script = defineComponent({
  name: FORM_ITEM_NAME,
  props: formItemProps,
  setup(props) {
    const {
      model,
      rules,
      layout,
      span,
      inlineItemWidth,
      showMessage,
      labelWidth,
      labelClass,
      labelPosition,
      disabled,
      align,
      addField,
      removeField
    } = inject(provideKey);
    const formItemProp = computed(() => {
      return props.prop || `${prefixCls}_${getCurrentInstance().uid}`;
    });
    const fieldValue = computed(() => {
      // 优先获取 value 的值
      if (props.value !== undefined) {
        return props.value;
      }

      // 不存在时获取 model[prop] 的值
      if (!model.value || !formItemProp.value) {
        return;
      }
      return get(model.value, formItemProp.value);
    });
    const initialValue = cloneDeep(fieldValue.value);
    const formItemRules = computed(() => {
      const _rules = [].concat(props.rules || []).concat(get(rules === null || rules === void 0 ? void 0 : rules.value, formItemProp.value) || []);
      return _rules;
    });

    /**
     * 规则校验结果逻辑: 仅存最后一条校验规则的逻辑
     *      存在问题: 如果同时触发两个规则 A|B，规则 A 先触发校验且不通过，接着规则 B 触发校验且通过，规则 A 结果会不展示
     */
    const validateDisabled = ref(false); // 是否触发校验的标志
    const validateStatus = ref(VALIDATE_STATUS.DEFAULT);
    const validateMessage = ref(VALIDATE_MESSAGE_DEFAULT);
    const setValidateInfo = function () {
      let status = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : VALIDATE_STATUS.DEFAULT;
      let message = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : VALIDATE_MESSAGE_DEFAULT;
      validateStatus.value = status;
      validateMessage.value = message;
    };
    /** 错误展示逻辑: 就近原则【formItem 权重更高】  */
    const formItemShowMessage = computed(() => (props.showMessage === null ? showMessage.value : props.showMessage) && validateStatus.value === VALIDATE_STATUS.ERROR);
    const formItemDisabled = computed(() => {
      if (!isNil(props.disabled)) {
        return props.disabled;
      }
      return disabled.value;
    });
    const formItemRequired = computed(() => formItemRules.value.length > 0 && formItemRules.value.some(_ => _.required));
    const formItemClass = computed(() => [prefixCls,
    // inlineFormItem 定宽情况: Form 传入 inlineItemWidth, 此时 inlineItemWidth 优先级最高
    // inlineFormItem 自适应情况: 同时支持 form、formItem 传入 span, 此时 formItem 优先级更高
    layout.value === FORM_LAYOUT.INLINE && !inlineItemWidth.value && `${prefixCls}-span-${Math.ceil(props.span || span.value)}`, labelPosition.value !== LABEL_POSITION.LEFT && `${prefixCls}-${labelPosition.value}`, validateStatus.value === VALIDATE_STATUS.ERROR && 'is-error',
    // 校验错误: is-error
    FORM_ITEM_ALIGN.includes(props.align || align.value) && `${prefixCls}-align-${props.align || align.value}`].filter(Boolean));
    const formItemLabelClass = computed(() => [`${prefixCls}-label`, formItemRequired.value && 'is-required',
    // 必填校验: is-required
    labelClass.value, props.labelClass].filter(Boolean));
    const formItemLabelStyle = computed(() => ({
      width: pxfy(props.labelWidth || labelWidth.value)
    }));

    /** 校验规则的类型: 默认 String  */
    let ruleDefaultType = RULE_TYPE_DEFAULT;
    const setRuleDefaultType = function () {
      let val = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : RULE_TYPE_DEFAULT;
      ruleDefaultType = val;
    };
    const validateRules = async function () {
      let trigger = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : TRIGGER_TYPE_DEFAULT;
      // fieldValue.value computed 执行后再进行校验
      await nextTick();
      if (validateDisabled.value) {
        validateDisabled.value = false;
        return;
      }

      /**
       * 过滤符合条件的 triggersRules
       *
       *  未指定具体 trigger 类型，则直接返回 rule 规则
       *  指定具体 trigger 类型:
       *     当 rule.trigger 未填写时, 则直接返回 rule 规则【没写 trigger 默认各种类型都可以触发该规则】
       *     当 rule.trigger 填写时, 需要按指定类型过滤【分 Array| String】
       */
      const triggersRules = !trigger ? formItemRules.value : formItemRules.value.filter(rule => !rule.trigger || (isArray(rule.trigger) ? rule.trigger.includes(trigger) : rule.trigger === trigger));

      // 处理 rule 规则里面是自定义 validator
      const activeRules = triggersRules.map(rule => {
        const shallowClonedRule = Object.assign({}, rule);
        if (shallowClonedRule.validator) {
          shallowClonedRule.validator = wrapValidator(shallowClonedRule.validator, false);
        }
        if (shallowClonedRule.asyncValidator) {
          shallowClonedRule.asyncValidator = wrapValidator(shallowClonedRule.asyncValidator, true);
        }
        if (!shallowClonedRule.type) {
          shallowClonedRule.type = ruleDefaultType;
        }
        return shallowClonedRule;
      });
      if (!activeRules.length) {
        return Promise.resolve();
      }

      // 开始规则校验
      const descriptor = {};
      descriptor[formItemProp.value] = activeRules;
      const validatorModel = {};
      validatorModel[formItemProp.value] = fieldValue.value;
      const validator = new Schema(descriptor);
      try {
        await Promise.resolve(validator.validate(validatorModel));
        setValidateInfo(VALIDATE_STATUS.SUCCESS);
      } catch (errObj) {
        if (errObj.errors) {
          const error = errObj.errors[0];
          setValidateInfo(VALIDATE_STATUS.ERROR, error.message);
          return Promise.reject([_objectSpread(_objectSpread({}, error), {}, {
            message: error.message,
            descriptor: descriptor[formItemProp.value] || null
          })]);
        }
      }
    };

    // 验证表单项
    const validate = async function () {
      let trigger = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : TRIGGER_TYPE_DEFAULT;
      try {
        await validateRules(trigger);
      } catch (err) {}
    };
    const clearValidate = () => {
      setValidateInfo();
      validateDisabled.value = false;
    };
    const resetField = () => {
      setValidateInfo();
      validateDisabled.value = true; // 在表单重置行为，不应触发校验

      // reset initialValue
      set(model.value, formItemProp.value, cloneDeep(initialValue));

      // reset validateDisabled after onFieldChange triggered
      nextTick(() => {
        validateDisabled.value = false;
      });
    };
    addField(formItemProp.value, {
      prop: formItemProp.value,
      value: fieldValue.value,
      rules: formItemRules.value,
      validateRules,
      clearValidate,
      resetField
    });
    onBeforeUnmount(() => {
      removeField(formItemProp.value);
    });
    provide(FORM_ITEM_INJECTION_KEY, {
      validate,
      setRuleDefaultType,
      isError: computed(() => {
        return validateStatus.value === VALIDATE_STATUS.ERROR;
      }),
      isFormDisabled: formItemDisabled
    });
    return {
      prefixCls,
      formItemClass,
      formItemLabelClass,
      formItemLabelStyle,
      formItemShowMessage,
      validateMessage,
      validate,
      clearValidate,
      formItemRules
    };
  }
});

function render(_ctx, _cache, $props, $setup, $data, $options) {
  return openBlock(), createElementBlock("div", {
    class: normalizeClass(_ctx.formItemClass)
  }, [_ctx.label || _ctx.$slots.label ? (openBlock(), createElementBlock("span", {
    key: 0,
    class: normalizeClass(_ctx.formItemLabelClass),
    style: normalizeStyle(_ctx.formItemLabelStyle)
  }, [renderSlot(_ctx.$slots, "label", {}, () => [createTextVNode(toDisplayString(_ctx.label), 1 /* TEXT */)])], 6 /* CLASS, STYLE */)) : createCommentVNode("v-if", true), createElementVNode("div", {
    class: normalizeClass(`${_ctx.prefixCls}-content`),
    style: normalizeStyle(_ctx.contentStyle)
  }, [renderSlot(_ctx.$slots, "default"), createVNode(Transition, {
    name: "fes-fade"
  }, {
    default: withCtx(() => [_ctx.formItemShowMessage ? (openBlock(), createElementBlock("div", {
      key: 0,
      class: normalizeClass(`${_ctx.prefixCls}-error`)
    }, toDisplayString(_ctx.validateMessage), 3 /* TEXT, CLASS */)) : createCommentVNode("v-if", true)]),
    _: 1 /* STABLE */
  })], 6 /* CLASS, STYLE */)], 2 /* CLASS */);
}

script.render = render;
script.__file = "components/form/formItem.vue";

export { script as default };
