import { defineComponent, ref, onMounted, onBeforeUnmount, createVNode } from 'vue';
import { partition } from 'lodash-es';
import '../../../utils/index.mjs';
import upload from './request.mjs';
import uid from './uid.mjs';
import attrAccept from './attr-accept.mjs';
import traverseFileTree from './traverseFileTree.mjs';
import { uploadProps } from './interface.mjs';
import { pickAttrs } from '../../../utils/lang/pickAttrs.mjs';

var AjaxUpload = /* @__PURE__ */ defineComponent({
  compatConfig: {
    MODE: 3
  },
  name: "AjaxUploader",
  inheritAttrs: false,
  props: uploadProps(),
  setup(props, {
    slots,
    attrs,
    expose
  }) {
    const uid$1 = ref(uid());
    const reqs = {};
    const fileInput = ref();
    let isMounted = false;
    const processFile = async (file, fileList) => {
      const {
        beforeUpload
      } = props;
      let transformedFile = file;
      if (beforeUpload) {
        try {
          transformedFile = await beforeUpload(file, fileList);
        } catch (e) {
          transformedFile = false;
        }
        if (transformedFile === false) {
          return {
            origin: file,
            parsedFile: null,
            action: null,
            data: null
          };
        }
      }
      const {
        action
      } = props;
      let mergedAction;
      if (typeof action === "function")
        mergedAction = await action(file);
      else
        mergedAction = action;
      const {
        data
      } = props;
      let mergedData;
      if (typeof data === "function")
        mergedData = await data(file);
      else
        mergedData = data;
      const parsedData = (typeof transformedFile === "object" || typeof transformedFile === "string") && transformedFile ? transformedFile : file;
      let parsedFile;
      if (parsedData instanceof File)
        parsedFile = parsedData;
      else
        parsedFile = new File([parsedData], file.name, {
          type: file.type
        });
      const mergedParsedFile = parsedFile;
      mergedParsedFile.uid = file.uid;
      return {
        origin: file,
        data: mergedData,
        parsedFile: mergedParsedFile,
        action: mergedAction
      };
    };
    const post = ({
      data,
      origin,
      action,
      parsedFile
    }) => {
      if (!isMounted)
        return;
      const {
        onStart,
        customRequest,
        name,
        headers,
        withCredentials,
        method
      } = props;
      const {
        uid: uid2
      } = origin;
      const request = customRequest || upload;
      const requestOption = {
        action,
        filename: name,
        data,
        file: parsedFile,
        headers,
        withCredentials,
        method: method || "post",
        onProgress: (e) => {
          const {
            onProgress
          } = props;
          onProgress == null ? void 0 : onProgress(e, parsedFile);
        },
        onSuccess: (ret, xhr) => {
          const {
            onSuccess
          } = props;
          onSuccess == null ? void 0 : onSuccess(ret, parsedFile, xhr);
          delete reqs[uid2];
        },
        onError: (err, ret) => {
          const {
            onError
          } = props;
          onError == null ? void 0 : onError(err, ret, parsedFile);
          delete reqs[uid2];
        }
      };
      onStart(origin);
      reqs[uid2] = request(requestOption);
    };
    const reset = () => {
      uid$1.value = uid();
    };
    const abort = (file) => {
      if (file) {
        const uid2 = file.uid ? file.uid : file;
        if (reqs[uid2] && reqs[uid2].abort)
          reqs[uid2].abort();
        delete reqs[uid2];
      } else {
        Object.keys(reqs).forEach((uid2) => {
          if (reqs[uid2] && reqs[uid2].abort)
            reqs[uid2].abort();
          delete reqs[uid2];
        });
      }
    };
    onMounted(() => {
      isMounted = true;
    });
    onBeforeUnmount(() => {
      isMounted = false;
      abort();
    });
    const uploadFiles = (files) => {
      const originFiles = [...files];
      const postFiles = originFiles.map((file) => {
        file.uid = uid();
        return processFile(file, originFiles);
      });
      Promise.all(postFiles).then((fileList) => {
        const {
          onBatchStart
        } = props;
        onBatchStart == null ? void 0 : onBatchStart(fileList.map(({
          origin,
          parsedFile
        }) => ({
          file: origin,
          parsedFile
        })));
        fileList.filter((file) => file.parsedFile !== null).forEach((file) => {
          post(file);
        });
      });
    };
    const onChange = (e) => {
      const {
        accept,
        directory
      } = props;
      const {
        files
      } = e.target;
      const acceptedFiles = [...files].filter((file) => !directory || attrAccept(file, accept));
      uploadFiles(acceptedFiles);
      reset();
    };
    const onClick = (e) => {
      const el = fileInput.value;
      if (!el)
        return;
      const {
        onClick: onClick2
      } = props;
      el.click();
      if (onClick2)
        onClick2(e);
    };
    const onKeyDown = (e) => {
      if (e.key === "Enter")
        onClick(e);
    };
    const onFileDrop = (e) => {
      const {
        multiple
      } = props;
      e.preventDefault();
      if (e.type === "dragover")
        return;
      if (props.directory) {
        traverseFileTree(Array.prototype.slice.call(e.dataTransfer.items), uploadFiles, (_file) => attrAccept(_file, props.accept));
      } else {
        const files = partition(Array.prototype.slice.call(e.dataTransfer.files), (file) => attrAccept(file, props.accept));
        let successFiles = files[0];
        const errorFiles = files[1];
        if (multiple === false)
          successFiles = successFiles.slice(0, 1);
        uploadFiles(successFiles);
        if (errorFiles.length && props.onReject)
          props.onReject(errorFiles);
      }
    };
    expose({
      abort
    });
    return () => {
      const {
        componentTag: Tag,
        prefixCls,
        disabled,
        id,
        multiple,
        accept,
        capture,
        directory,
        openFileDialogOnClick,
        onMouseenter,
        onMouseleave,
        ...otherProps
      } = props;
      const cls = {
        [prefixCls]: true,
        [`${prefixCls}-disabled`]: disabled,
        [attrs.class]: !!attrs.class
      };
      const dirProps = directory ? {
        directory: "directory",
        webkitdirectory: "webkitdirectory"
      } : {};
      const events = disabled ? {} : {
        onClick: openFileDialogOnClick ? onClick : () => {
        },
        onKeydown: openFileDialogOnClick ? onKeyDown : () => {
        },
        onMouseenter,
        onMouseleave,
        onDrop: onFileDrop,
        onDragover: onFileDrop,
        tabindex: "0"
      };
      return createVNode(Tag, {
        ...events,
        "class": cls,
        "role": "button",
        "style": attrs.style
      }, {
        default: () => {
          var _a;
          return [createVNode("input", {
            ...pickAttrs(otherProps, {
              aria: true,
              data: true
            }),
            "id": id,
            "type": "file",
            "ref": fileInput,
            "onClick": (e) => e.stopPropagation(),
            "onCancel": (e) => e.stopPropagation(),
            "key": uid$1.value,
            "style": {
              display: "none"
            },
            "accept": accept,
            ...dirProps,
            "multiple": multiple,
            "onChange": onChange,
            ...capture != null ? {
              capture
            } : {}
          }, null), (_a = slots.default) == null ? void 0 : _a.call(slots)];
        }
      });
    };
  }
});

export { AjaxUpload as default };
//# sourceMappingURL=AjaxUploader.mjs.map
