import { isArray, isFunction } from "../../../../../@vue/shared/dist/shared.esm-bundler.mjs";
import { getProp } from "../../../utils/objects.mjs";
import { debugWarn } from "../../../utils/error.mjs";
import { useNamespace } from "../../../hooks/use-namespace/index.mjs";
import { formEmits, formProps } from "./form.mjs";
import { formContextKey } from "./constants.mjs";
import { useFormSize } from "./hooks/use-form-common-props.mjs";
import { useFormLabelWidth, filterFields } from "./utils.mjs";
import { defineComponent, ref, reactive, computed, watch, provide, toRefs, createElementBlock, openBlock, normalizeClass, renderSlot } from "vue";
import cloneDeep from "../../../../../lodash-es/cloneDeep.mjs";
import castArray from "../../../../../lodash-es/castArray.mjs";
const COMPONENT_NAME = "ElForm";
var form_vue_vue_type_script_setup_true_lang_default = /* @__PURE__ */ defineComponent({
  name: COMPONENT_NAME,
  __name: "form",
  props: formProps,
  emits: formEmits,
  setup(__props, { expose: __expose, emit: __emit }) {
    const props = __props;
    const emit = __emit;
    const formRef = ref();
    const fields = reactive([]);
    const initialValues = /* @__PURE__ */ new Map();
    const formSize = useFormSize();
    const ns = useNamespace("form");
    const formClasses = computed(() => {
      const { labelPosition, inline } = props;
      return [
        ns.b(),
        ns.m(formSize.value || "default"),
        {
          [ns.m(`label-${labelPosition}`)]: labelPosition,
          [ns.m("inline")]: inline
        }
      ];
    });
    const getField = (prop) => {
      return filterFields(fields, [prop])[0];
    };
    const addField = (field) => {
      fields.push(field);
      if (field.propString) if (initialValues.has(field.propString)) field.setInitialValue(initialValues.get(field.propString));
      else initialValues.set(field.propString, cloneDeep(field.fieldValue));
    };
    const removeField = (field) => {
      if (field.prop) fields.splice(fields.indexOf(field), 1);
    };
    const setInitialValues = (initModel) => {
      if (!props.model) {
        debugWarn(COMPONENT_NAME, "model is required for setInitialValues to work.");
        return;
      }
      if (!initModel) {
        debugWarn(COMPONENT_NAME, "initModel is required for setInitialValues to work.");
        return;
      }
      for (const key of initialValues.keys()) initialValues.set(key, cloneDeep(getProp(initModel, key).value));
      fields.forEach((field) => {
        if (field.prop) field.setInitialValue(getProp(initModel, field.prop).value);
      });
    };
    const resetFields = (properties = []) => {
      if (!props.model) {
        debugWarn(COMPONENT_NAME, "model is required for resetFields to work.");
        return;
      }
      filterFields(fields, properties).forEach((field) => field.resetField());
      const activePropStrings = new Set(fields.map((f) => f.propString).filter(Boolean));
      const propsToCheck = properties.length > 0 ? castArray(properties).map((p) => isArray(p) ? p.join(".") : p) : [...initialValues.keys()];
      for (const propString of propsToCheck) if (!activePropStrings.has(propString) && initialValues.has(propString)) getProp(props.model, propString).value = cloneDeep(initialValues.get(propString));
    };
    const clearValidate = (props2 = []) => {
      filterFields(fields, props2).forEach((field) => field.clearValidate());
    };
    const isValidatable = computed(() => {
      const hasModel = !!props.model;
      if (!hasModel) debugWarn(COMPONENT_NAME, "model is required for validate to work.");
      return hasModel;
    });
    const obtainValidateFields = (props2) => {
      if (fields.length === 0) return [];
      const filteredFields = filterFields(fields, props2);
      if (!filteredFields.length) {
        debugWarn(COMPONENT_NAME, "please pass correct props!");
        return [];
      }
      return filteredFields;
    };
    const validate = async (callback) => validateField(void 0, callback);
    const doValidateField = async (props2 = []) => {
      if (!isValidatable.value) return false;
      const fields2 = obtainValidateFields(props2);
      if (fields2.length === 0) return true;
      let validationErrors = {};
      for (const field of fields2) try {
        await field.validate("");
        if (field.validateState === "error" && !field.error) field.resetField();
      } catch (fields3) {
        validationErrors = {
          ...validationErrors,
          ...fields3
        };
      }
      if (Object.keys(validationErrors).length === 0) return true;
      return Promise.reject(validationErrors);
    };
    const validateField = async (modelProps = [], callback) => {
      var _a;
      let result = false;
      const shouldThrow = !isFunction(callback);
      try {
        result = await doValidateField(modelProps);
        if (result === true) await (callback == null ? void 0 : callback(result));
        return result;
      } catch (e) {
        if (e instanceof Error) throw e;
        const invalidFields = e;
        if (props.scrollToError) {
          if (formRef.value) (_a = formRef.value.querySelector(`.${ns.b()}-item.is-error`)) == null ? void 0 : _a.scrollIntoView(props.scrollIntoViewOptions);
        }
        !result && await (callback == null ? void 0 : callback(false, invalidFields));
        return shouldThrow && Promise.reject(invalidFields);
      }
    };
    const scrollToField = (prop) => {
      var _a;
      const field = getField(prop);
      if (field) (_a = field.$el) == null ? void 0 : _a.scrollIntoView(props.scrollIntoViewOptions);
    };
    watch(() => props.rules, () => {
      if (props.validateOnRuleChange) validate().catch((err) => debugWarn(err));
    }, {
      deep: true,
      flush: "post"
    });
    provide(formContextKey, reactive({
      ...toRefs(props),
      emit,
      resetFields,
      clearValidate,
      validateField,
      getField,
      addField,
      removeField,
      setInitialValues,
      ...useFormLabelWidth()
    }));
    __expose({
      validate,
      validateField,
      resetFields,
      clearValidate,
      scrollToField,
      getField,
      fields,
      setInitialValues
    });
    return (_ctx, _cache) => {
      return openBlock(), createElementBlock("form", {
        ref_key: "formRef",
        ref: formRef,
        class: normalizeClass(formClasses.value)
      }, [renderSlot(_ctx.$slots, "default")], 2);
    };
  }
});
export {
  form_vue_vue_type_script_setup_true_lang_default as default
};
