<script setup lang="ts">
import { computed, ref, useSlots } from 'vue'
import CustomIcon from '../custom-icon/custom-icon.vue'
import { fetchUpload } from '@/apis/upload'

interface Emit {
  (e: 'formatError'): void
  (e: 'oversize'): void
  (e: 'update:imageUrl', value: string): void
}

const props = defineProps({
  imageUrl: {
    type: String,
    default: '',
  },
  maxImageSize: {
    type: Number,
    default: 1024 * 1024 * 3,
  },
  listType: {
    type: Array,
    default: () => ['jpg', 'png', 'jpeg', 'svg', 'gif'],
  },
  width: {
    type: Number,
    default: 72,
  },
  height: {
    type: Number,
    default: 72,
  },
})

const emit = defineEmits<Emit>()

const slots = useSlots()

const uploadLoading = ref(false)
const isShowImageMask = ref(false)

const uploadImageUrl = computed({
  get() {
    return props.imageUrl
  },
  set(value: string) {
    emit('update:imageUrl', value)
  },
})

const uploadImageType = computed(() => {
  return props.listType.map((typeItem) => 'image/' + typeItem).join(',')
})

async function handleUploadImage(event: any) {
  const e = window.event || event
  const file = e.target.files[0]

  if (!props.listType.includes(file.type.split('/')[1])) {
    emit('formatError')
    return
  }

  if (file.size > props.maxImageSize) {
    emit('oversize')
    return
  }

  const URL = window.URL || window.webkitURL
  const img = new Image()
  img.src = URL.createObjectURL(file)

  img.onload = async function () {
    const formData = new FormData()
    formData.append('file', file)

    uploadLoading.value = true

    const res = await fetchUpload(formData).finally(() => {
      uploadLoading.value = false
      event.target.value = null
    })

    if (res.code === 0) {
      uploadImageUrl.value = res.data as string
    }
  }
}
</script>

<template>
  <div class="relative overflow-hidden rounded-lg" :style="{ height: height + 'px', width: width + 'px' }">
    <NSpin :show="uploadLoading" class="h-full w-full">
      <label
        class="hover:border-blue flex cursor-pointer flex-col items-center justify-center rounded-lg"
        :class="uploadImageUrl ? '' : 'border border-gray-200'"
        :style="{ height: height + 'px', width: width + 'px' }"
        for="upload"
      >
        <CustomIcon v-if="!uploadLoading" class="text-lg" icon="mingcute:add-line" />
      </label>
    </NSpin>

    <div
      v-show="uploadImageUrl"
      class="absolute left-0 top-0 h-full w-full"
      @mouseenter="isShowImageMask = true"
      @mouseleave="isShowImageMask = false"
    >
      <img :src="uploadImageUrl" class="h-full w-full object-cover" />

      <label
        v-show="isShowImageMask"
        class="absolute left-0 top-0 flex h-full w-full cursor-pointer items-center justify-center bg-[#151b2680]"
        for="upload"
      >
        <slot v-if="slots.mask" name="mask" />
        <CustomIcon v-else class="text-base text-white" icon="lucide:edit" />
      </label>

      <input id="upload" type="file" :accept="uploadImageType" class="hidden" @change="handleUploadImage" />
    </div>
  </div>
</template>
