import _defineProperty from '@babel/runtime/helpers/esm/defineProperty';
import { ref, computed, provide, toRefs, watch } from 'vue';
import { isArray, isEqual, isFunction } from 'lodash-es';
import { noop, hasOwn } from '../_util/utils';
import useFormAdaptor from '../_util/use/useFormAdaptor';
import getPrefixCls from '../_util/getPrefixCls';
import { useNormalModel } from '../_util/use/useModel';
import defaultRequest from './ajax';
import { key } from './const';

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('upload');
function genUid(seed) {
  return Date.now() + seed;
}
function getFile(rawFile, uploadFiles) {
  return uploadFiles.find(file => file.uid === rawFile.uid);
}
var useUpload = (props, emit) => {
  const isDragger = ref(false);
  const inputRef = ref();
  const requestList = ref({});
  let tempIndex = 1;
  const [uploadFiles, updateUploadFiles] = useNormalModel(props, emit, {
    prop: 'fileList'
  });
  function initFile(rawFile) {
    const uid = genUid(tempIndex++);
    rawFile.uid = uid;
    const file = {
      name: rawFile.name,
      percentage: 0,
      status: 'ready',
      size: rawFile.size,
      raw: rawFile,
      uid,
      url: ''
    };
    return file;
  }
  function abort(file) {
    const _requestList = requestList.value;
    if (file) {
      const uid = file.uid;
      if (_requestList[uid]) {
        _requestList[uid].abort();
      }
    } else {
      Object.keys(_requestList).forEach(uid => {
        const _uid = uid;
        if (_requestList[_uid]) {
          _requestList[_uid].abort();
        }
        delete _requestList[_uid];
      });
    }
  }
  function onStart(rawFile) {
    const file = initFile(rawFile);
    if (props.listType === 'picture-card') {
      try {
        file.url = URL.createObjectURL(rawFile);
      } catch (error) {
        console.error('[Upload]', error);
        emit('error', {
          error,
          file,
          fileList: uploadFiles.value
        });
      }
    }
    uploadFiles.value.push(file);
    emit('change', {
      file,
      fileList: uploadFiles.value
    });
  }
  function onExceed(files) {
    emit('exceed', {
      files,
      fileList: uploadFiles.value
    });
  }
  function onProgress(_ref) {
    let {
      event,
      rawFile
    } = _ref;
    const file = getFile(rawFile, uploadFiles.value);
    if (!file) {
      return;
    }
    file.status = 'uploading';
    file.percentage = event.percent || 0;
    emit('progress', {
      event,
      file,
      fileList: uploadFiles.value
    });
  }
  function onSuccess(_ref2) {
    let {
      response,
      rawFile
    } = _ref2;
    const file = getFile(rawFile, uploadFiles.value);
    if (!file) {
      return;
    }
    file.status = 'success';
    file.response = response;
    emit('success', {
      response,
      file,
      fileList: uploadFiles.value
    });
    emit('change', {
      file,
      fileList: uploadFiles.value
    });
  }
  function onError(_ref3) {
    let {
      error,
      rawFile
    } = _ref3;
    const uploadFilesValue = uploadFiles.value;
    const file = getFile(rawFile, uploadFilesValue);
    if (!file) {
      return;
    }
    file.status = 'error';
    emit('error', {
      error,
      file,
      fileList: uploadFilesValue
    });
    emit('change', {
      file,
      fileList: uploadFilesValue
    });
  }
  function onRemove(rawFile, file) {
    const uploadFilesValue = uploadFiles.value;
    file = file || getFile(rawFile, uploadFilesValue);
    if (!file) {
      return;
    }
    const doRemove = () => {
      abort(file);
      uploadFilesValue.splice(uploadFilesValue.indexOf(file), 1);
      emit('remove', {
        file,
        fileList: uploadFilesValue
      });
      emit('change', {
        file,
        fileList: uploadFilesValue
      });
    };
    if (!props.beforeRemove) {
      return doRemove();
    }
    if (isFunction(props.beforeRemove)) {
      const before = props.beforeRemove(file, uploadFilesValue);
      if (before instanceof Promise) {
        before.then(() => {
          doRemove();
        }).catch(noop);
      } else if (before !== false) {
        doRemove();
      }
    }
  }
  const httpRequest = computed(() => {
    var _props$httpRequest;
    return (_props$httpRequest = props.httpRequest) !== null && _props$httpRequest !== void 0 ? _props$httpRequest : defaultRequest;
  });
  const post = rawFile => {
    if (!props.httpRequest && !props.action) {
      onRemove(rawFile);
      console.error('[FUpload] 需配置action地址，才能执行上传');
      return;
    }
    const {
      uid
    } = rawFile;
    const options = {
      headers: props.headers,
      withCredentials: props.withCredentials,
      data: props.data,
      file: rawFile,
      fileName: props.name,
      action: props.action,
      timeout: props.timeout,
      transformResponse: props.transformResponse,
      onProgress: e => {
        onProgress({
          event: e,
          rawFile
        });
      },
      onSuccess: res => {
        onSuccess({
          response: res,
          rawFile
        });
        delete requestList.value[uid];
      },
      onError: err => {
        onError({
          error: err,
          rawFile
        });
        delete requestList.value[uid];
      }
    };
    const req = httpRequest.value(options);
    requestList.value[uid] = req;
    if (req instanceof Promise) {
      req.then(options.onSuccess, options.onError);
    }
  };
  const upload = async rawFile => {
    inputRef.value.value = null;
    if (!props.beforeUpload) {
      return post(rawFile);
    }
    try {
      let processedFile = await props.beforeUpload(rawFile);
      if (processedFile === false) {
        return onRemove(rawFile);
      }
      const fileType = Object.prototype.toString.call(processedFile);
      if (fileType === '[object File]' || fileType === '[object Blob]') {
        if (fileType === '[object Blob]') {
          processedFile = new File([processedFile], rawFile.name, {
            type: rawFile.type
          });
        }
        Object.keys(rawFile).forEach(p => {
          if (hasOwn(rawFile, p)) {
            processedFile[p] = rawFile[p];
          }
        });
        post(processedFile);
      } else {
        post(rawFile);
      }
    } catch (e) {
      onRemove(rawFile);
    }
  };
  const onUploadFiles = files => {
    files = Array.from(files);
    if (props.multipleLimit && props.fileList.length + files.length > props.multipleLimit) {
      onExceed(files);
      return;
    }
    let postFiles = files;
    if (!props.multiple) {
      postFiles = postFiles.slice(0, 1);
    }
    if (postFiles.length === 0) {
      return;
    }
    postFiles.forEach(rawFile => {
      onStart(rawFile);
      upload(rawFile);
    });
  };

  // 表单组件的总体disabled状态
  const {
    isFormDisabled
  } = useFormAdaptor();
  provide(key, _objectSpread(_objectSpread({}, toRefs(props)), {}, {
    disabled: computed(() => {
      return props.disabled || isFormDisabled.value;
    }),
    prefixCls,
    uploadFiles,
    onRemove,
    onUploadFiles,
    inputRef,
    isDragger
  }));
  watch(() => props.fileList, fileList => {
    if (!isArray(fileList)) {
      fileList = [];
    }
    if (!isEqual(uploadFiles.value, fileList)) {
      uploadFiles.value = fileList.map(file => {
        return _objectSpread(_objectSpread({}, file), {}, {
          uid: file.uid || genUid(tempIndex++),
          status: file.status || 'success'
        });
      });
    }
  }, {
    immediate: true,
    deep: true
  });
  function clearFiles() {
    updateUploadFiles([]);
  }
  function addFile(rawFile) {
    if (!rawFile) {
      return;
    }
    if (props.multipleLimit && props.fileList.length + 1 > props.multipleLimit) {
      onExceed([rawFile]);
      return;
    }
    onStart(rawFile);
    upload(rawFile);
  }
  function removeFile(file) {
    if (!file) {
      return;
    }
    onRemove(null, file);
  }
  return {
    uploadFiles,
    isDragger,
    clearFiles,
    addFile,
    removeFile
  };
};

export { useUpload as default };
