import { defineComponent, computed, ref, watch, createVNode } from 'vue';
import { isEqual } from 'lodash-es';
import scrollIntoView from 'scroll-into-view-if-needed';
import '../../../utils/index.mjs';
import useConfigInject from '../../config-provider/src/hooks/useConfigInject.mjs';
import '../../config-provider/index.mjs';
import useStyle from '../style/index.mjs';
import useForm from './useForm.mjs';
import { useProvideForm } from './context.mjs';
import { allPromiseFinish } from './utils/asyncUtil.mjs';
import { defaultValidateMessages } from './utils/messages.mjs';
import { getNamePath, cloneByNamePathList, containsNamePath } from './utils/valueUtil.mjs';
import AFormItem from './FormItem.mjs';
import { formProps } from './props.mjs';
import { toArray } from '../../../utils/lang/array.mjs';
import { initDefaultProps } from '../../../utils/vue/initDefaultProps.mjs';
import { useProviderSize } from '../../config-provider/src/context/sizeContext.mjs';
import { useProviderDisabled } from '../../config-provider/src/context/disabledContext.mjs';
import { useInjectGlobalForm } from '../../config-provider/src/context/context.mjs';
import { classNames } from '../../../utils/dom/class.mjs';
import { devWarning } from '../../../utils/log.mjs';

function isEqualName(name1, name2) {
  return isEqual(toArray(name1), toArray(name2));
}
var AForm = /* @__PURE__ */ defineComponent({
  compatConfig: {
    MODE: 3
  },
  name: "AForm",
  inheritAttrs: false,
  props: initDefaultProps(formProps(), {
    layout: "horizontal",
    hideRequiredMark: false,
    colon: true
  }),
  Item: AFormItem,
  useForm,
  // emits: ['finishFailed', 'submit', 'finish', 'validate'],
  setup(props, {
    emit,
    slots,
    expose,
    attrs
  }) {
    const {
      prefixCls,
      direction,
      form: contextForm,
      size,
      disabled
    } = useConfigInject("form", props);
    const requiredMark = computed(() => props.requiredMark === "" || props.requiredMark);
    const mergedRequiredMark = computed(() => {
      var _a;
      if (requiredMark.value !== void 0)
        return requiredMark.value;
      if (contextForm && ((_a = contextForm.value) == null ? void 0 : _a.requiredMark) !== void 0)
        return contextForm.value.requiredMark;
      if (props.hideRequiredMark)
        return false;
      return true;
    });
    useProviderSize(size);
    useProviderDisabled(disabled);
    const mergedColon = computed(() => {
      var _a, _b;
      return (_b = props.colon) != null ? _b : (_a = contextForm.value) == null ? void 0 : _a.colon;
    });
    const {
      validateMessages: globalValidateMessages
    } = useInjectGlobalForm();
    const validateMessages = computed(() => {
      return {
        ...defaultValidateMessages,
        ...globalValidateMessages.value,
        ...props.validateMessages
      };
    });
    const [wrapSSR, hashId] = useStyle(prefixCls);
    const formClassName = computed(() => classNames(prefixCls.value, {
      [`${prefixCls.value}-${props.layout}`]: true,
      [`${prefixCls.value}-hide-required-mark`]: mergedRequiredMark.value === false,
      [`${prefixCls.value}-rtl`]: direction.value === "rtl",
      [`${prefixCls.value}-${size.value}`]: size.value
    }, hashId.value));
    const lastValidatePromise = ref();
    const fields = {};
    const addField = (eventKey, field) => {
      fields[eventKey] = field;
    };
    const removeField = (eventKey) => {
      delete fields[eventKey];
    };
    const getFieldsByNameList = (nameList) => {
      const provideNameList = !!nameList;
      const namePathList = provideNameList ? toArray(nameList).map(getNamePath) : [];
      if (!provideNameList) {
        return Object.values(fields);
      } else {
        return Object.values(fields).filter((field) => namePathList.findIndex((namePath) => isEqualName(namePath, field.fieldName.value)) > -1);
      }
    };
    const resetFields = (name) => {
      if (!props.model) {
        devWarning(false, "Form", "model is required for resetFields to work.");
        return;
      }
      getFieldsByNameList(name).forEach((field) => {
        field.resetField();
      });
    };
    const clearValidate = (name) => {
      getFieldsByNameList(name).forEach((field) => {
        field.clearValidate();
      });
    };
    const scrollToField = (name, options = {}) => {
      const fields2 = getFieldsByNameList(name ? [name] : void 0);
      if (fields2.length) {
        const fieldId = fields2[0].fieldId.value;
        const node = fieldId ? document.getElementById(fieldId) : null;
        if (node) {
          scrollIntoView(node, {
            scrollMode: "if-needed",
            block: "nearest",
            ...options
          });
        }
      }
    };
    const handleFinishFailed = (errorInfo) => {
      const {
        scrollToFirstError
      } = props;
      emit("finishFailed", errorInfo);
      if (scrollToFirstError && errorInfo.errorFields.length) {
        let scrollToFieldOptions = {};
        if (typeof scrollToFirstError === "object")
          scrollToFieldOptions = scrollToFirstError;
        scrollToField(errorInfo.errorFields[0].name, scrollToFieldOptions);
      }
    };
    const getFieldsValue = (nameList = true) => {
      if (nameList === true) {
        const allNameList = [];
        Object.values(fields).forEach(({
          namePath
        }) => {
          allNameList.push(namePath.value);
        });
        return cloneByNamePathList(props.model, allNameList);
      } else {
        return cloneByNamePathList(props.model, nameList);
      }
    };
    const validateFields = (nameList, options) => {
      devWarning(!(nameList instanceof Function), "Form", "validateFields/validateField/validate not support callback, please use promise instead");
      if (!props.model) {
        devWarning(false, "Form", "model is required for validateFields to work.");
        return Promise.reject("Form `model` is required for validateFields to work.");
      }
      const provideNameList = !!nameList;
      const namePathList = provideNameList ? toArray(nameList).map(getNamePath) : [];
      const promiseList = [];
      Object.values(fields).forEach((field) => {
        var _a;
        if (!provideNameList)
          namePathList.push(field.namePath.value);
        if (!((_a = field.rules) == null ? void 0 : _a.value.length))
          return;
        const fieldNamePath = field.namePath.value;
        if (!provideNameList || containsNamePath(namePathList, fieldNamePath)) {
          const promise = field.validateRules({
            validateMessages: validateMessages.value,
            ...options
          });
          promiseList.push(promise.then(() => ({
            name: fieldNamePath,
            errors: [],
            warnings: []
          })).catch((ruleErrors) => {
            const mergedErrors = [];
            const mergedWarnings = [];
            ruleErrors.forEach(({
              rule: {
                warningOnly
              },
              errors
            }) => {
              if (warningOnly)
                mergedWarnings.push(...errors);
              else
                mergedErrors.push(...errors);
            });
            if (mergedErrors.length) {
              return Promise.reject({
                name: fieldNamePath,
                errors: mergedErrors,
                warnings: mergedWarnings
              });
            }
            return {
              name: fieldNamePath,
              errors: mergedErrors,
              warnings: mergedWarnings
            };
          }));
        }
      });
      const summaryPromise = allPromiseFinish(promiseList);
      lastValidatePromise.value = summaryPromise;
      const returnPromise = summaryPromise.then(() => {
        if (lastValidatePromise.value === summaryPromise)
          return Promise.resolve(getFieldsValue(namePathList));
        return Promise.reject([]);
      }).catch((results) => {
        const errorList = results.filter((result) => result && result.errors.length);
        return Promise.reject({
          values: getFieldsValue(namePathList),
          errorFields: errorList,
          outOfDate: lastValidatePromise.value !== summaryPromise
        });
      });
      returnPromise.catch((e) => e);
      return returnPromise;
    };
    const validateField = (...args) => {
      return validateFields(...args);
    };
    const validate = (...args) => {
      return validateField(...args);
    };
    const handleSubmit = (e) => {
      e.preventDefault();
      e.stopPropagation();
      emit("submit", e);
      if (props.model) {
        const res = validateFields();
        res.then((values) => {
          emit("finish", values);
        }).catch((errors) => {
          handleFinishFailed(errors);
        });
      }
    };
    expose({
      resetFields,
      clearValidate,
      validateFields,
      getFieldsValue,
      validate,
      scrollToField
    });
    useProvideForm({
      model: computed(() => props.model),
      name: computed(() => props.name),
      labelAlign: computed(() => props.labelAlign),
      labelCol: computed(() => props.labelCol),
      labelWrap: computed(() => props.labelWrap),
      wrapperCol: computed(() => props.wrapperCol),
      vertical: computed(() => props.layout === "vertical"),
      colon: mergedColon,
      requiredMark: mergedRequiredMark,
      validateTrigger: computed(() => props.validateTrigger),
      rules: computed(() => props.rules),
      addField,
      removeField,
      onValidate: (name, status, errors) => {
        emit("validate", name, status, errors);
      },
      validateMessages
    });
    watch(() => props.rules, () => {
      if (props.validateOnRuleChange)
        validateFields();
    });
    return () => {
      var _a;
      return wrapSSR(createVNode("form", {
        ...attrs,
        "onSubmit": handleSubmit,
        "class": [formClassName.value, attrs.class]
      }, [(_a = slots.default) == null ? void 0 : _a.call(slots)]));
    };
  }
});

export { AForm as default };
//# sourceMappingURL=Form.mjs.map
