<template>
  <view :class="uploadClass" :style="uploadStyle">
    <view :class="bem.e('wrapper')">
      <sar-upload-preview
        v-for="(item, index) in innerValue"
        :key="index"
        :file="item.file"
        :url="item.url"
        :is-image="item.isImage"
        :is-video="item.isVideo"
        :status="item.status"
        :name="item.name"
        :message="item.message"
        :removable="removable"
        :before-remove="beforeRemove"
        :index="index"
        :disabled="isDisabled"
        :readonly="isReadonly"
        @remove="onRemove(index, item)"
        @image-click="onImageClick"
      />
      <view
        v-if="innerValue.length < maxCount"
        :class="bem.e('select')"
        @click="onSelect"
      >
        <slot name="select">
          <view :class="bem.e('select-icon')">
            <sar-icon name="plus" />
          </view>
        </slot>
      </view>
    </view>
  </view>
</template>

<script lang="ts">
import { defineComponent as _defineComponent } from "vue";
import { computed, ref, watch } from "vue";
import {
  classNames,
  stringifyStyle,
  createBem,
  getFileName,
  noop,
  isImageUrl,
  toArray
} from "../utils";
import SarUploadPreview from "../upload-preview/upload-preview.vue";
import SarIcon from "../icon/icon.vue";
import { chooseMedia } from "./utils";
import {
  uploadProps
} from "./common";
import { useFormContext, useFormItemContext } from "../form/common";
const __default__ = {
  options: {
    virtualHost: true,
    styleIsolation: "shared"
  }
};
export default /* @__PURE__ */ _defineComponent({
  ...__default__,
  __name: "upload",
  props: uploadProps,
  emits: ["update:model-value", "remove"],
  setup(__props, { expose: __expose, emit: __emit }) {
    __expose();
    const props = __props;
    const emit = __emit;
    const bem = createBem("upload");
    const formContext = useFormContext();
    const formItemContext = useFormItemContext();
    const isDisabled = computed(() => {
      return formContext?.disabled ?? props.disabled;
    });
    const isReadonly = computed(() => {
      return formContext?.readonly ?? props.readonly;
    });
    const innerValue = ref(props.modelValue || []);
    watch(
      () => props.modelValue,
      () => {
        innerValue.value = props.modelValue || [];
        if (props.validateEvent) {
          formItemContext?.onChange();
        }
      }
    );
    const limitCountNode = (files, next) => {
      const remainCount = props.maxCount - innerValue.value.length;
      if (files.length > remainCount) {
        files = files.slice(0, remainCount);
      }
      next(files);
    };
    const beforeReadNode = (files, next) => {
      Promise.allSettled(
        files.map(
          (file) => new Promise((resolve, reject) => {
            if (props.beforeRead) {
              const ret = props.beforeRead(file);
              if (!ret) {
                reject();
                return;
              }
              if (ret instanceof Promise) {
                ret.then((mayNewFile) => {
                  resolve(mayNewFile ?? file);
                }).catch(() => {
                  reject();
                });
                return;
              }
            }
            resolve(file);
          })
        )
      ).then((results) => {
        const fileList = [];
        results.forEach((result) => {
          if (result.status === "fulfilled") {
            fileList.push(result.value);
          }
        });
        next(fileList);
      });
    };
    const toUploadFileNode = (files, next) => {
      const fileList = files.map((file) => {
        return {
          file,
          name: file.path && getFileName(file.path)
        };
      });
      next(fileList);
    };
    const limitSizeNode = (fileList, next) => {
      const valid = [];
      const invalid = [];
      fileList.forEach((item) => {
        const file = item.file;
        if (file && (typeof props.maxSize === "function" && props.maxSize(file) || file.size && typeof props.maxSize === "number" && file.size > props.maxSize)) {
          invalid.push(item);
        } else {
          valid.push(item);
        }
      });
      if (invalid.length) {
        props.overSize?.(invalid);
      }
      if (valid.length) {
        innerValue.value = [...innerValue.value, ...valid];
        emit("update:model-value", innerValue.value);
        next(valid);
      }
    };
    const afterReadNode = (fileList) => {
      toArray(fileList).forEach((fileItem) => {
        props.afterRead?.(fileItem);
      });
    };
    function toChain(files) {
      const chain = [
        limitCountNode,
        beforeReadNode,
        toUploadFileNode,
        limitSizeNode,
        afterReadNode
      ].reduceRight(
        (next, node) => (data) => {
          node(data, next);
        },
        () => {
          null;
        }
      );
      chain(files);
    }
    const onSelect = () => {
      if (isDisabled.value || isReadonly.value || innerValue.value.length >= props.maxCount) {
        return;
      }
      chooseMedia({
        mediaType: props.accept,
        count: props.multiple ? 9999 : 1,
        sizeType: props.sizeType,
        sourceType: props.sourceType,
        maxDuration: props.maxDuration,
        camera: props.camera,
        success(result) {
          toChain(
            result.tempFiles.map((file) => {
              return {
                type: file.fileType,
                size: file.size,
                path: file.tempFilePath,
                duration: file.duration,
                width: file.width,
                height: file.height
              };
            })
          );
        },
        fail: noop
      });
    };
    const onRemove = (index, item) => {
      const list = innerValue.value.filter((_, i) => i !== index);
      innerValue.value = list;
      emit("update:model-value", list);
      emit("remove", index, item);
    };
    const onImageClick = (index) => {
      const currentFileItem = innerValue.value[index];
      const fileList = innerValue.value.filter(
        (item) => item.url && isImageUrl(item.url) || item.file?.type === "image"
      );
      const currentIndex = fileList.findIndex((item) => item === currentFileItem);
      const urls = fileList.map((item) => item.url || item.file?.path);
      uni.previewImage({
        urls,
        current: urls[currentIndex]
      });
    };
    const uploadClass = computed(() => {
      return classNames(
        bem.b(),
        bem.m("disabled", isDisabled.value),
        bem.m("readonly", isReadonly.value),
        props.rootClass
      );
    });
    const uploadStyle = computed(() => {
      return stringifyStyle(props.rootStyle);
    });
    const __returned__ = { props, emit, bem, formContext, formItemContext, isDisabled, isReadonly, innerValue, limitCountNode, beforeReadNode, toUploadFileNode, limitSizeNode, afterReadNode, toChain, onSelect, onRemove, onImageClick, uploadClass, uploadStyle, SarUploadPreview, SarIcon };
    return __returned__;
  }
});
</script>

<style lang="scss">
@use './index.scss';
</style>