import { defineComponent, shallowRef, computed, watchEffect, toRaw, nextTick, watch, onBeforeUnmount, reactive, createVNode, onMounted, Fragment } from 'vue';
import { CheckCircleFilled, ExclamationCircleFilled, CloseCircleFilled, LoadingOutlined } from '@ant-design/icons-vue';
import { cloneDeep, find } from 'lodash-es';
import '../../../utils/index.mjs';
import { Row } from '../../grid/index.mjs';
import useConfigInject from '../../config-provider/src/hooks/useConfigInject.mjs';
import useStyle from '../style/index.mjs';
import { validateRules } from './utils/validateUtil.mjs';
import { getNamePath } from './utils/valueUtil.mjs';
import { useInjectForm } from './context.mjs';
import FormItemLabel from './FormItemLabel.mjs';
import FormItemInput from './FormItemInput.mjs';
import { useProvideFormItemContext, FormItemInputContext } from './FormItemContext.mjs';
import useDebounce from './utils/useDebounce.mjs';
import { formItemProps } from './props.mjs';
import { warning } from '../../../utils/log.mjs';
import { toArray } from '../../../utils/lang/array.mjs';
import { classNames } from '../../../utils/dom/class.mjs';
import { filterEmpty } from '../../../utils/vue/props.mjs';

const iconMap = {
  success: CheckCircleFilled,
  warning: ExclamationCircleFilled,
  error: CloseCircleFilled,
  validating: LoadingOutlined
};
function getPropByPath(obj, namePathList, strict) {
  let tempObj = obj;
  const keyArr = namePathList;
  let i = 0;
  try {
    for (let len = keyArr.length; i < len - 1; ++i) {
      if (!tempObj && !strict)
        break;
      const key = keyArr[i];
      if (key in tempObj) {
        tempObj = tempObj[key];
      } else {
        if (strict)
          throw new Error("please transfer a valid name path to form item!");
        break;
      }
    }
    if (strict && !tempObj)
      throw new Error("please transfer a valid name path to form item!");
  } catch (error) {
    console.error("please transfer a valid name path to form item!");
  }
  return {
    o: tempObj,
    k: keyArr[i],
    v: tempObj ? tempObj[keyArr[i]] : void 0
  };
}
let indexGuid = 0;
const defaultItemNamePrefixCls = "form_item";
var AFormItem = /* @__PURE__ */ defineComponent({
  compatConfig: {
    MODE: 3
  },
  name: "AFormItem",
  inheritAttrs: false,
  __ANT_NEW_FORM_ITEM: true,
  props: formItemProps(),
  slots: Object,
  setup(props, {
    slots,
    attrs,
    expose
  }) {
    warning(props.prop === void 0, "`prop` is deprecated. Please use `name` instead.");
    const eventKey = `form-item-${++indexGuid}`;
    const {
      prefixCls
    } = useConfigInject("form", props);
    const [wrapSSR, hashId] = useStyle(prefixCls);
    const itemRef = shallowRef();
    const formContext = useInjectForm();
    const fieldName = computed(() => props.name || props.prop);
    const errors = shallowRef([]);
    const validateDisabled = shallowRef(false);
    const inputRef = shallowRef();
    const namePath = computed(() => {
      const val = fieldName.value;
      return getNamePath(val);
    });
    const fieldId = computed(() => {
      if (!namePath.value.length) {
        return void 0;
      } else {
        const formName = formContext.name.value;
        const mergedId = namePath.value.join("_");
        return formName ? `${formName}_${mergedId}` : `${defaultItemNamePrefixCls}_${mergedId}`;
      }
    });
    const getNewFieldValue = () => {
      const model = formContext.model.value;
      if (model && fieldName.value)
        return getPropByPath(model, namePath.value, true).v;
    };
    const fieldValue = computed(() => getNewFieldValue());
    const initialValue = shallowRef(cloneDeep(fieldValue.value));
    const mergedValidateTrigger = computed(() => {
      let validateTrigger = props.validateTrigger !== void 0 ? props.validateTrigger : formContext.validateTrigger.value;
      validateTrigger = validateTrigger === void 0 ? "change" : validateTrigger;
      return toArray(validateTrigger);
    });
    const rulesRef = computed(() => {
      let formRules = formContext.rules.value;
      const selfRules = props.rules;
      const requiredRule = props.required !== void 0 ? {
        required: !!props.required,
        trigger: mergedValidateTrigger.value
      } : [];
      const prop = getPropByPath(formRules, namePath.value);
      formRules = formRules ? prop.o[prop.k] || prop.v : [];
      const rules = [].concat(selfRules || formRules || []);
      if (find(rules, (rule) => rule.required))
        return rules;
      else
        return rules.concat(requiredRule);
    });
    const getIsRequired = computed(() => {
      const rules = rulesRef.value;
      let isRequired = false;
      if (rules && rules.length) {
        rules.every((rule) => {
          if (rule.required) {
            isRequired = true;
            return false;
          }
          return true;
        });
      }
      return isRequired || props.required;
    });
    const validateState = shallowRef();
    watchEffect(() => {
      validateState.value = props.validateStatus;
    });
    const messageVariables = computed(() => {
      let variables = {};
      if (typeof props.label === "string")
        variables.label = props.label;
      else if (props.name)
        variables.label = String(props.name);
      if (props.messageVariables)
        variables = {
          ...variables,
          ...props.messageVariables
        };
      return variables;
    });
    const validateRules$1 = (options) => {
      if (namePath.value.length === 0)
        return;
      const {
        validateFirst = false
      } = props;
      const {
        triggerName
      } = options || {};
      let filteredRules = rulesRef.value;
      if (triggerName) {
        filteredRules = filteredRules.filter((rule) => {
          const {
            trigger
          } = rule;
          if (!trigger && !mergedValidateTrigger.value.length)
            return true;
          const triggerList = toArray(trigger || mergedValidateTrigger.value);
          return triggerList.includes(triggerName);
        });
      }
      if (!filteredRules.length)
        return Promise.resolve();
      const promise = validateRules(namePath.value, fieldValue.value, filteredRules, {
        validateMessages: formContext.validateMessages.value,
        ...options
      }, validateFirst, messageVariables.value);
      validateState.value = "validating";
      errors.value = [];
      promise.catch((e) => e).then((results = []) => {
        if (validateState.value === "validating") {
          const res = results.filter((result) => result && result.errors.length);
          validateState.value = res.length ? "error" : "success";
          errors.value = res.map((r) => r.errors);
          formContext.onValidate(fieldName.value, !errors.value.length, errors.value.length ? toRaw(errors.value[0]) : null);
        }
      });
      return promise;
    };
    const onFieldBlur = () => {
      validateRules$1({
        triggerName: "blur"
      });
    };
    const onFieldChange = () => {
      if (validateDisabled.value) {
        validateDisabled.value = false;
        return;
      }
      validateRules$1({
        triggerName: "change"
      });
    };
    const clearValidate = () => {
      validateState.value = props.validateStatus;
      validateDisabled.value = false;
      errors.value = [];
    };
    const resetField = () => {
      var _a;
      validateState.value = props.validateStatus;
      validateDisabled.value = true;
      errors.value = [];
      const model = formContext.model.value || {};
      const value = fieldValue.value;
      const prop = getPropByPath(model, namePath.value, true);
      if (Array.isArray(value))
        prop.o[prop.k] = [].concat((_a = initialValue.value) != null ? _a : []);
      else
        prop.o[prop.k] = initialValue.value;
      nextTick(() => {
        validateDisabled.value = false;
      });
    };
    const htmlFor = computed(() => {
      return props.htmlFor === void 0 ? fieldId.value : props.htmlFor;
    });
    const onLabelClick = () => {
      const id = htmlFor.value;
      if (!id || !inputRef.value)
        return;
      const control = inputRef.value.$el.querySelector(`[id="${id}"]`);
      if (control && control.focus)
        control.focus();
    };
    expose({
      onFieldBlur,
      onFieldChange,
      clearValidate,
      resetField
    });
    useProvideFormItemContext({
      id: fieldId,
      onFieldBlur: () => {
        if (props.autoLink)
          onFieldBlur();
      },
      onFieldChange: () => {
        if (props.autoLink)
          onFieldChange();
      },
      clearValidate
    }, computed(() => {
      return !!(props.autoLink && formContext.model.value && fieldName.value);
    }));
    let registered = false;
    watch(fieldName, (val) => {
      if (val) {
        if (!registered) {
          registered = true;
          formContext.addField(eventKey, {
            fieldValue,
            fieldId,
            fieldName,
            resetField,
            clearValidate,
            namePath,
            validateRules: validateRules$1,
            rules: rulesRef
          });
        }
      } else {
        registered = false;
        formContext.removeField(eventKey);
      }
    }, {
      immediate: true
    });
    onBeforeUnmount(() => {
      formContext.removeField(eventKey);
    });
    const debounceErrors = useDebounce(errors);
    const mergedValidateStatus = computed(() => {
      if (props.validateStatus !== void 0)
        return props.validateStatus;
      else if (debounceErrors.value.length)
        return "error";
      return validateState.value;
    });
    const itemClassName = computed(() => ({
      [`${prefixCls.value}-item`]: true,
      [hashId.value]: true,
      // Status
      [`${prefixCls.value}-item-has-feedback`]: mergedValidateStatus.value && props.hasFeedback,
      [`${prefixCls.value}-item-has-success`]: mergedValidateStatus.value === "success",
      [`${prefixCls.value}-item-has-warning`]: mergedValidateStatus.value === "warning",
      [`${prefixCls.value}-item-has-error`]: mergedValidateStatus.value === "error",
      [`${prefixCls.value}-item-is-validating`]: mergedValidateStatus.value === "validating",
      [`${prefixCls.value}-item-hidden`]: props.hidden
    }));
    const formItemInputContext = reactive({});
    FormItemInputContext.useProvide(formItemInputContext);
    watchEffect(() => {
      let feedbackIcon;
      if (props.hasFeedback) {
        const IconNode = mergedValidateStatus.value && iconMap[mergedValidateStatus.value];
        feedbackIcon = IconNode ? createVNode("span", {
          "class": classNames(`${prefixCls.value}-item-feedback-icon`, `${prefixCls.value}-item-feedback-icon-${mergedValidateStatus.value}`)
        }, [createVNode(IconNode, null, null)]) : null;
      }
      Object.assign(formItemInputContext, {
        status: mergedValidateStatus.value,
        hasFeedback: props.hasFeedback,
        feedbackIcon,
        isFormItemInput: true
      });
    });
    const marginBottom = shallowRef(null);
    const showMarginOffset = shallowRef(false);
    const updateMarginBottom = () => {
      if (itemRef.value) {
        const itemStyle = getComputedStyle(itemRef.value);
        marginBottom.value = Number.parseInt(itemStyle.marginBottom, 10);
      }
    };
    onMounted(() => {
      watch(showMarginOffset, () => {
        if (showMarginOffset.value)
          updateMarginBottom();
      }, {
        flush: "post",
        immediate: true
      });
    });
    const onErrorVisibleChanged = (nextVisible) => {
      if (!nextVisible)
        marginBottom.value = null;
    };
    return () => {
      var _a, _b;
      if (props.noStyle)
        return (_a = slots.default) == null ? void 0 : _a.call(slots);
      const help = (_b = props.help) != null ? _b : slots.help ? filterEmpty(slots.help()) : null;
      const withHelp = !!(help !== void 0 && help !== null && Array.isArray(help) && help.length || debounceErrors.value.length);
      showMarginOffset.value = withHelp;
      return wrapSSR(createVNode("div", {
        "class": [itemClassName.value, withHelp ? `${prefixCls.value}-item-with-help` : "", attrs.class],
        "ref": itemRef
      }, [createVNode(Row, {
        ...attrs,
        "class": `${prefixCls.value}-row`,
        "key": "row"
      }, {
        default: () => {
          var _a2, _b2;
          return createVNode(Fragment, null, [createVNode(FormItemLabel, {
            ...props,
            "htmlFor": htmlFor.value,
            "required": getIsRequired.value,
            "requiredMark": formContext.requiredMark.value,
            "prefixCls": prefixCls.value,
            "onClick": onLabelClick,
            "label": props.label
          }, {
            label: slots.label,
            tooltip: slots.tooltip
          }), createVNode(FormItemInput, {
            ...props,
            "errors": help !== void 0 && help !== null ? toArray(help) : debounceErrors.value,
            "marginBottom": marginBottom.value,
            "prefixCls": prefixCls.value,
            "status": mergedValidateStatus.value,
            "ref": inputRef,
            "help": help,
            "extra": (_b2 = props.extra) != null ? _b2 : (_a2 = slots.extra) == null ? void 0 : _a2.call(slots),
            "onErrorVisibleChanged": onErrorVisibleChanged
          }, {
            default: slots.default
          })]);
        }
      }), !!marginBottom.value && createVNode("div", {
        "class": `${prefixCls.value}-margin-offset`,
        "style": {
          marginBottom: `-${marginBottom.value}px`
        }
      }, null)]));
    };
  }
});

export { AFormItem as default };
//# sourceMappingURL=FormItem.mjs.map
