<template>
  <div class="image-uploader">
    <!-- 图片列表 -->
    <div class="image-center">
      <Draggable
        v-if="imageLists.length"
        v-model="imageLists"
        :item-key="draggableKey"
        class="image-list"
        animation=""
        ghost-class="sortable-ghost"
        chosen-class="sortable-chosen"
      >
        <template #item="{ element: image }">
          <div
            class="image-card"
            :class="{ selected: selectedIds.includes(image.image_url) }"
          >
            <div class="checkbox">
              <el-checkbox
                :model-value="selectedIds.includes(image.image_url)"
                @change="toggleSelect(image.image_url)"
              />
            </div>
            <div class="btn_wrap">
              <button type="button" @click.stop="seeImage(image.image_url)">
                <el-icon><ZoomIn /></el-icon>
              </button>
            </div>
            <div class="preview_img">
              <img
                :src="getImageUrl(image.image_url, 80, 80)"
                :alt="image.id"
              />
            </div>
            <div v-if="image.id" class="actions">
              {{ image.id }}
            </div>
          </div>
        </template>
      </Draggable>
      <!-- 上传区域 -->
      <div v-if="isShowUpload" class="upload-area">
        <div class="color-image-item-icon-plus" @click="triggerFileInput">
          <el-icon><Plus /></el-icon>
        </div>
        <input
          ref="fileInputRef"
          type="file"
          accept="image/*"
          multiple
          style="display: none"
          @change="handleFileUpload"
        />
      </div>
    </div>

    <!-- 底部操作栏 -->
    <div v-if="imageLists.length" class="actions-bar">
      <el-button v-if="isMoreCheck" type="success" @click="toggleSelectAll">
        {{ isAllSelected ? '取消全选' : '选择全部' }}
      </el-button>
      <el-button
        v-if="isShowUpload"
        type="danger"
        plain
        :disabled="!selectedIds.length"
        @click="deleteSelected"
      >
        删除选中 ({{ selectedIds.length }})
      </el-button>
    </div>
    <el-image-viewer
      v-if="previewVisible"
      :url-list="previewImageList"
      :initial-index="previewIndex"
      @close="previewVisible = false"
    />
  </div>
</template>

<script setup lang="ts">
import {
  ref,
  computed,
  watch,
  onBeforeUnmount,
  defineProps,
  defineEmits,
  defineExpose,
} from 'vue'
import { ElMessage, ElMessageBox } from 'element-plus'
import { Plus, ZoomIn } from '@element-plus/icons-vue'
import Draggable from 'vuedraggable'
const props = defineProps({
  modelValue: {
    type: Array as () => ImageInfo[],
    required: true,
  },
  maxCount: {
    type: Number,
  },
  maxSizeMB: {
    type: Number,
  },
  // 是否显示上传按钮?仅作列表展示？默认显示上传
  isShowUpload: {
    type: Boolean,
    default: true,
  },
  // 选中图片要单选？多选？默认多选
  isMoreCheck: {
    type: Boolean,
    default: true,
  },
})

const emit = defineEmits<{
  (e: 'update:modelValue', value: ImageInfo[]): void
  (e: 'change', value: ImageInfo[]): void
  (e: 'list-change', value: (string | null)[]): void
}>()

const imageLists = ref<ImageInfo[]>(props.modelValue || [])
const selectedIds = ref<(string | null)[]>([])
const fileInputRef = ref<HTMLInputElement>()

// 监听外部 modelValue 变化（外部修改时同步到本地）
watch(
  () => props.modelValue,
  (newVal: ImageInfo[]) => {
    imageLists.value = newVal || []
  },
  { deep: true },
)

// 是否全选
const isAllSelected = computed(() => {
  return (
    imageLists.value.length > 0 &&
    selectedIds.value.length === imageLists.value.length
  )
})

// 拖拽组件的 key 函数
const draggableKey = (item: ImageInfo) => item.image_url

// 监听外部 modelValue 变化
const syncModelValue = () => {
  emit('update:modelValue', imageLists.value)
  emit('change', imageLists.value)
}
const seeImage = (item: string) => {
  // 预览列表：所有图片的完整 URL
  previewImageList.value = imageLists.value.map(
    (img: ImageInfo) => getImageUrl(img.image_url) as string,
  )
  previewIndex.value = imageLists.value.findIndex(
    (img: ImageInfo) => img.image_url === item,
  )
  previewVisible.value = true
}
const previewVisible = ref(false)
const previewIndex = ref(0)
const previewImageList = ref<string[]>([])
// 触发隐藏文件选择框
const triggerFileInput = () => {
  fileInputRef.value?.click()
}

import { uploadImageApi } from '@/api/common'
import { ImageInfo, UploadResponse } from '@/types/api/product'
import { getImageUrl } from '@/utils/product'
import { ElLoading } from 'element-plus'

const uploadLoading = ref(false)
const handleFileUpload = async (files: Event) => {
  const fileList = (files.target as HTMLInputElement).files
  if (!fileList) return

  const requestList: Promise<UploadResponse>[] = []
  for (let i = 0; i < fileList.length; i++) {
    const file = fileList[i]
    const formData = new FormData()
    formData.append('file', file)
    formData.append('businessType', 'product')
    requestList.push(uploadImageApi(formData))
  }

  const loadingInstance = ElLoading.service({
    lock: true,
    text: `正在上传 ${fileList.length} 个文件...`,
    background: 'rgba(0, 0, 0, 0.7)',
  })

  uploadLoading.value = true
  if (fileInputRef.value) {
    fileInputRef.value.value = ''
  }

  try {
    const res = await Promise.all(requestList)
    const createImage: ImageInfo[] = []
    res.forEach((item, index) => {
      const imgInfo = {
        sort: imageLists.value.length + index,
        image_url: item.filePath,
        id: null,
        product_id: null,
      }
      createImage.push(imgInfo)
    })
    imageLists.value = [...imageLists.value, ...createImage]
    syncModelValue()
  } catch (e) {
    console.error(e)
    ElMessage.error('上传失败，请重试')
  } finally {
    // 关闭 loading 遮罩
    loadingInstance.close()
    uploadLoading.value = false
  }
}

// const handleFileUpload = (event: Event) => {
//   const input = event.target as HTMLInputElement
//   const files = Array.from(input.files || [])
//   if (!files.length) return

//   // 校验数量
//   if (
//     props.maxCount &&
//     imageLists.value.length + files.length > props.maxCount
//   ) {
//     ElMessage.warning(`最多只能上传 ${props.maxCount} 张图片`)
//     return
//   }

//   // 逐个处理文件
//   for (const file of files) {
//     if (!file.type.startsWith('image/')) {
//       ElMessage.warning(`文件 ${file.name} 不是图片，已跳过`)
//       continue
//     }
//     const maxSize = (props.maxSizeMB || 5) * 1024 * 1024
//     if (file.size > maxSize) {
//       ElMessage.warning(
//         `图片 ${file.name} 超过 ${props.maxSizeMB || 5}MB，已跳过`,
//       )
//       continue
//     }
//     const url = URL.createObjectURL(file)
//     imageLists.value.push({
//       id: null,
//       image_url: url,
//     })
//   }

//   syncModelValue()
//   input.value = '' // 清空，允许重复上传同一文件
// }
// 切换单个图片选中状态
const toggleSelect = (imageUrl: string | null) => {
  if (!imageUrl) return // 无效 URL 直接忽略
  const isMoreCheck = props.isMoreCheck ?? true // 默认多选
  const index = selectedIds.value.indexOf(imageUrl)
  if (isMoreCheck) {
    // 多选：切换选中状态
    if (index === -1) {
      selectedIds.value.push(imageUrl)
    } else {
      selectedIds.value.splice(index, 1)
    }
  } else {
    // 单选：如果点击的是已选中项，则取消；否则清空后选中当前项
    if (index !== -1) {
      selectedIds.value = []
    } else {
      selectedIds.value = [imageUrl]
    }
  }
  emit('list-change', selectedIds.value)
}
const clear = () => {
  selectedIds.value = []
}
// 全选/取消全选
const toggleSelectAll = () => {
  if (isAllSelected.value) {
    selectedIds.value = []
  } else {
    selectedIds.value = imageLists.value.map((img: ImageInfo) => img.image_url)
  }
  emit('list-change', selectedIds.value)
}

// 删除选中的图片
const deleteSelected = async () => {
  if (!selectedIds.value.length) return
  try {
    await ElMessageBox.confirm('确定将选中的图片删除？', '提示', {
      confirmButtonText: '确定',
      cancelButtonText: '取消',
      type: 'warning',
    })
  } catch {
    return
  }
  // 过滤掉选中的图片
  const newImages = imageLists.value.filter(
    (img: ImageInfo) => !selectedIds.value.includes(img.image_url),
  )
  // 释放被删除图片的 URL
  imageLists.value.forEach((img: ImageInfo) => {
    if (selectedIds.value.includes(img.image_url)) {
      URL.revokeObjectURL(img.image_url)
    }
  })
  imageLists.value = newImages
  selectedIds.value = []
  syncModelValue()
}

// 组件卸载时释放所有 object URL
onBeforeUnmount(() => {
  imageLists.value.forEach((img: ImageInfo) => {
    URL.revokeObjectURL(img.image_url)
  })
})

// 对外暴露方法（可选）
defineExpose({
  clear,
  imageLists,
  reset: () => {
    imageLists.value.forEach((img: ImageInfo) =>
      URL.revokeObjectURL(img.image_url),
    )
    imageLists.value = []
    selectedIds.value = []
    syncModelValue()
  },
})
</script>

<style scoped lang="scss">
.image-uploader {
  .image-center {
    display: flex;
    align-items: flex-start;
    gap: 16px;
    padding-left: 16px;
  }
  .upload-area {
    display: flex;
    align-items: center;
    gap: 12px;
    margin: 16px 0;
    .tip {
      font-size: 12px;
      color: #909399;
    }
  }

  .image-list {
    display: flex;
    flex-wrap: wrap;
    gap: 16px;
    margin: 16px 0;

    // 拖拽样式
    :deep(.sortable-ghost) {
      opacity: 0.4;
      background: #409eff;
    }
    :deep(.sortable-chosen) {
      cursor: move;
    }
    :deep(.image-card) {
      cursor: grab;
      &:active {
        cursor: grabbing;
      }
    }

    .image-card {
      position: relative;
      width: 100px;
      border: 1px solid #dcdfe6;
      border-radius: 8px;
      overflow: hidden;
      transition: all 0.2s;

      &.selected {
        border-color: #409eff;
        box-shadow: 0 0 0 2px rgba(64, 158, 255, 0.2);
      }

      .checkbox {
        position: absolute;
        top: 4px;
        left: 4px;
        z-index: 1;
        background: rgba(255, 255, 255, 0.7);
        border-radius: 4px;
        padding: 2px;
      }
      .btn_wrap {
        display: none;
        position: absolute;
        top: 0;
        right: 0;
        bottom: 0;
        left: 0;
        justify-content: center;
        align-items: center;
        background: rgba(0, 0, 0, 0.5);
        button {
          color: #fff;
          font-size: 26px;
        }
      }
      &:hover .btn_wrap {
        display: flex;
      }
      .preview_img {
        width: 100%;
        height: 100px;
        display: flex;
        align-items: center;
        justify-content: center;
        background: #f5f7fa;
        img {
          max-width: 100%;
          max-height: 100%;
          object-fit: contain;
        }
      }

      .actions {
        display: flex;
        justify-content: center;
        padding: 8px;
        border-top: 1px solid #ebeef5;
        background: #fff;
      }
    }
  }

  .actions-bar {
    display: flex;
    justify-content: flex-end;
    gap: 12px;
    padding-top: 8px;
    border-top: 1px solid #ebeef5;
  }
}
.color-image-item-icon-plus {
  width: 98px;
  height: 98px;
  border-radius: 8px;
  border: 1px solid #ebeef5;
  cursor: pointer;
  position: relative;
  display: flex;
  align-items: center;
  justify-content: center;
  i {
    color: #777;
    font-size: 24px;
  }
}
</style>
