<template>
  <div class="upload-container">
    <div v-for="(image, index) in uploadedImages" :key="index" class="image-preview">
      <el-image
        :src="image.url"
        :zoom-rate="1.2"
        :max-scale="7"
        :min-scale="0.2"
        :preview-src-list="uploadedImages.map((item) => item.url)"
        show-progress
        :initial-index="index"
        fit="contain"
      />
      <div class="delete-icon" @click="removeImage(index)">×</div>
    </div>

    <div
      v-show="!isMaximum"
      class="upload-box"
      :class="{ dragging: isDragging }"
      @click="!isMaximum && triggerUpload()"
      @drop.prevent="onDrop"
      @dragover.prevent
      @dragenter.prevent="onDragEnter"
      @dragleave.prevent="onDragLeave"
    >
      <input
        ref="fileInput"
        type="file"
        accept=".jpg,.jpeg,.png"
        multiple
        @change="handleFileChange"
        style="display: none"
        :disabled="isMaximum"
      />
      <div class="upload-icons">
        <div class="plus-icon">
          <el-icon><Plus /></el-icon>
        </div>
        <div class="camera-icon">
          <el-icon><Camera /></el-icon>
        </div>
      </div>
    </div>
  </div>
</template>

<script lang="ts" setup>
  import { ref, reactive, computed, watch, onUnmounted } from 'vue';
  import { Camera, Plus } from '@element-plus/icons-vue';
  import { ElMessage, ElMessageBox } from 'element-plus';
  import type { ImageItem } from '@/types/disaster-control';

  const props = defineProps({
    maxCount: {
      type: Number,
      default: 9,
    },
    maxSize: {
      type: Number,
      default: 10, // 默认10MB
    },
    acceptTypes: {
      type: Array as () => string[],
      default: () => ['.jpg', '.jpeg', '.png'],
    },
    imageList: {
      type: Array as () => string[],
    },
  });
  const emit = defineEmits(['uploadSuccess']);

  const fileInput = ref<HTMLInputElement | null>(null);
  const uploadedImages = reactive<ImageItem[]>([]);

  // 计算属性：是否已达到最大上传数量
  const isMaximum = computed(() => {
    return uploadedImages.length >= props.maxCount;
  });

  const isDragging = ref(false);

  const onDragEnter = () => {
    if (!isMaximum.value) {
      isDragging.value = true;
    }
  };

  const onDragLeave = () => {
    isDragging.value = false;
  };

  const onDrop = (e: DragEvent) => {
    isDragging.value = false;
    if (!isMaximum.value && e.dataTransfer?.files) {
      handleDrop(e);
    }
  };

  const triggerUpload = () => {
    fileInput.value?.click();
  };

  const handleFileChange = (e: Event) => {
    const target = e.target as HTMLInputElement;
    if (target.files) {
      addFiles(Array.from(target.files));
    }
  };

  const handleDrop = (e: DragEvent) => {
    if (e.dataTransfer?.files) {
      addFiles(Array.from(e.dataTransfer.files));
    }
  };

  // 检查文件是否已存在
  const isFileExist = (file: File): boolean => {
    // 通过文件名和文件大小判断是否为同一文件
    return uploadedImages.some((item) => item.name === file.name && item.size === file.size);
  };

  const checkFileValid = (file: File): boolean => {
    // 检查文件是否已上传
    if (isFileExist(file)) {
      ElMessage.warning(`文件"${file.name}"已上传过了`);
      return false;
    }

    // 检查文件类型
    const type = file.type.toLowerCase();
    const isValidType = type.includes('jpeg') || type.includes('jpg') || type.includes('png');

    if (!isValidType) {
      ElMessage.error(`文件"${file.name}"格式不正确，请上传jpg、png或jpeg格式的图片`);
      return false;
    }

    // 检查文件大小
    const sizeInMB = file.size / (1024 * 1024);
    if (sizeInMB > props.maxSize) {
      ElMessage.error(`文件"${file.name}"大小超过${props.maxSize}MB限制`);
      return false;
    }

    return true;
  };

  const addFiles = (files: File[]) => {
    // 过滤出有效的图片文件
    const validFiles = files.filter(checkFileValid);

    // 检查是否超过最大数量限制
    const remainingSlots = props.maxCount - uploadedImages.length;
    if (validFiles.length > remainingSlots) {
      ElMessage.warning(`最多只能上传${props.maxCount}张图片`);
    }

    const filesToAdd = validFiles.slice(0, remainingSlots);

    // 添加到已上传列表
    filesToAdd.forEach((file) => {
      const url = URL.createObjectURL(file);
      uploadedImages.push({
        file,
        url,
        name: file.name,
        size: file.size,
      });
    });

    // 触发更新事件
    if (filesToAdd.length > 0) {
      emitChange();
    }
  };

  const removeImage = (index: number) => {
    // 释放对象URL以避免内存泄漏
    URL.revokeObjectURL(uploadedImages[index].url);
    uploadedImages.splice(index, 1);
    ElMessage.success('删除成功');
    emitChange();
  };

  const removeAllImages = () => {
    uploadedImages.forEach((item) => {
      URL.revokeObjectURL(item.url);
    });
    uploadedImages.length = 0;
  };

  const getUploadedImages = () => {
    return uploadedImages;
  };

  defineExpose({
    removeAllImages,
    getUploadedImages,
  });

  const emitChange = () => {
    const files = uploadedImages.filter((item) => item.file).map((item) => item.file);
    emit('uploadSuccess', files);
  };
  watch(
    () => props.imageList,
    (newVal) => {
      if (!newVal) return;
      const urlList = newVal.map((item) => {
        return {
          url: item,
        };
      });
      uploadedImages.push(...urlList);
    },
    {
      immediate: true,
    },
  );
  onUnmounted(() => {
    removeAllImages();
  });
</script>

<style lang="scss" scoped>
  .upload-container {
    display: flex;
    flex-wrap: wrap;
    gap: 5px;
    width: 100%;
  }

  .upload-box,
  .image-preview {
    width: 100px;
    height: 100px;
    border-radius: 4px;
  }

  .upload-box {
    @include flex-center;
    border: 1px dashed rgba($text-color, 0.15);
    cursor: pointer;
    transition: all 0.3s;

    &:hover {
      border-color: $primary-color;
    }

    &.dragging {
      border-color: $primary-color;
      border-width: 2px;
      background-color: rgba($primary-color, 0.05);
      transform: scale(1.02);
      box-shadow: 0 0 8px rgba($primary-color, 0.3);
    }
  }

  .upload-icons {
    @include flex-center;
    flex-direction: column;
    gap: 5px;
    color: #b5b8be;
    .plus-icon {
      @include flex-center;
      width: 26px;
      height: 26px;
      font-size: 20px;
    }
    .camera-icon {
      @include flex-center;
      width: 35px;
      height: 30px;
      font-size: 30px;
    }
  }

  .image-preview {
    position: relative;
    overflow: hidden;
    .el-image {
      width: 100%;
      height: 100%;
    }

    .delete-icon {
      position: absolute;
      top: 0;
      right: 0;
      width: 20px;
      height: 20px;
      display: flex;
      justify-content: center;
      align-items: center;
      background-color: rgba(0, 0, 0, 0.5);
      color: white;
      cursor: pointer;
      font-size: 16px;
      border-radius: 0 0 0 4px;
    }
  }
</style>
