<script lang="ts" setup>
import { useUserStore } from '@/stores/user'
import { ACCESS_TOKEN } from '@/utils/constants'
import { ElMessage } from 'element-plus'
import { isAbsolutePath, ossUpload } from '@/utils/utils'
import config from '@/config/defaultSetting'
import type { UploadProps, UploadFile } from 'element-plus'
import type { BasicFormItem } from '@/types/form'

interface Props {
  modelValue: any
  item?: BasicFormItem
  size?: number | string
  iconSize?: number | string
  fileSize?: number | string
  uploadApi?: string
  oss?: boolean
  limit?: number
}
const props = withDefaults(defineProps<Props>(), {
  size: '148px',
  iconSize: '28px',
  uploadApi: config.uploadApi,
  fileSize: 10,
  oss: config.oss,
  limit: 1
})
const emits = defineEmits(['update:modelValue'])

const baseApi = import.meta.env.VITE_BASE_API
const modelValue = computed({
  get: () => props.modelValue,
  set: value => emits('update:modelValue', value)
})

const user = useUserStore()
const headers = reactive({
  [ACCESS_TOKEN]: user.token
})

const limit = Number(props.limit) || 1

// 生成图片地址
const prefix = props.oss ? config.ossHost : baseApi
const genImageUrl = (url: string) => {
  if (url.startsWith('blob:') || isAbsolutePath(url)) {
    return url
  } else {
    return prefix + url
  }
}

const uploadRef = ref()
// 在上传之前对文件进行验证
const fileSize = Number(props.fileSize) || 10
const beforeUpload: UploadProps['beforeUpload'] = rawFile => {
  if (rawFile.size / 1024 / 1024 > fileSize) {
    ElMessage.error(`图片大小不能超过${fileSize}MB!`)
    return false
  }
  return true
}

// 图片上传成功
const uploadList = ref([...props.modelValue])
const handleUploadSuccess: UploadProps['onSuccess'] = (response, uploadFile: UploadFile, uploadFiles: UploadFile[]) => {
  if (response.success || response.code === 200) {
    // 附加oss路径
    uploadList.value = uploadFiles
  } else {
    ElMessage.error(response.msg)
  }
}
// 删除图片
const handleRemove = (file: UploadFile) => {
  uploadRef.value.handleRemove(file)
  uploadList.value = modelValue.value
}
// 图片预览
const showViewer = ref(false)
const previewIndex = ref(0)
const previewList = computed(() => modelValue.value.map((item: any) => genImageUrl(item.url)))
const handlePreview = (file: UploadFile) => {
  previewIndex.value = modelValue.value.findIndex((item: any) => item.url === file.url)
  showViewer.value = true
}
const closeViewer = () => {
  showViewer.value = false
}

// 动态属性
const attrs: any = props.oss ? { 'http-request': ossUpload } : {}
if (props.item) {
  // 接口需要的属性
  props.item.extra = computed(() => uploadList.value.map((item: any) => item.response?.url || item.url))
  if (!props.item.props?.onSuccess) {
    attrs['on-success'] = handleUploadSuccess
  }
}
</script>

<template>
  <el-upload
    ref="uploadRef"
    v-model:file-list="modelValue"
    :class="{ 'is-disabled': modelValue.length >= limit }"
    :action="isAbsolutePath(props.uploadApi) ? props.uploadApi : baseApi + props.uploadApi"
    :headers="headers"
    :before-upload="beforeUpload"
    :limit="limit"
    list-type="picture-card"
    accept="image/*"
    v-bind="{ ...attrs, ...$attrs }"
  >
    <el-icon class="avatar-uploader-icon" :style="{ fontSize: iconSize }"><Plus /></el-icon>
    <template #file="{ file }">
      <el-image class="el-upload-list__item-thumbnail" :src="genImageUrl(file.url)" fit="cover" />
      <span class="el-upload-list__item-actions">
        <span class="el-upload-list__item-preview" @click="handlePreview(file)">
          <el-icon><zoom-in /></el-icon>
        </span>

        <span class="el-upload-list__item-delete" @click="handleRemove(file)">
          <el-icon><Delete /></el-icon>
        </span>
      </span>
    </template>
  </el-upload>
  <el-image-viewer v-if="showViewer" :url-list="previewList" :initial-index="previewIndex" @close="closeViewer" />
</template>

<style lang="scss" scoped>
:deep(.el-upload) {
  width: v-bind(size);
  height: v-bind(size);
  border: 1px dashed var(--el-border-color);
  border-radius: 6px;
  cursor: pointer;
  position: relative;
  overflow: hidden;
  transition: var(--el-transition-duration-fast);

  &:hover {
    border-color: var(--el-color-primary);
  }
}
:deep(.el-upload-list--picture-card .el-upload-list__item) {
  width: v-bind(size);
  height: v-bind(size);
}
.is-disabled :deep(.el-upload--picture-card) {
  display: none;
}
</style>
