<template>
  <div class="file-image-group">
    <!-- 缩略图网格 -->
    <div class="image-grid" :class="gridClass" :style="gridStyle">
      <div
        v-for="(fileData, index) in fileIds"
        :key="`${getFileKey(fileData)}_${index}`"
        class="file-image-thumb-wrapper"
        :style="thumbStyle"
        @click="handleImageClick(index)"
      >
        <!-- 加载中 -->
        <div v-if="loadingMap[index]" class="thumb-loading">
          <a-spin size="small" />
        </div>
        <!-- 加载失败 -->
        <div v-else-if="errorMap[index]" class="thumb-error">
          <a-icon type="picture" />
        </div>
        <!-- 图片 -->
        <template v-else>
          <img
            v-if="urlsMap[index]"
            :src="urlsMap[index]"
            :alt="`${altPrefix}${index + 1}`"
            class="thumb-img"
          />
          <div v-else class="thumb-loading">
            <a-spin size="small" />
          </div>
        </template>
        <div class="thumb-overlay">
          <a-icon type="eye" />
        </div>
      </div>
    </div>

    <div v-if="!fileIds || fileIds.length === 0" class="empty-state">
      <a-icon type="camera" />
      <span>{{ emptyText }}</span>
    </div>

    <!-- 画廊预览 -->
    <template v-if="galleryVisible">
      <image-preview-modal
        :visible="galleryVisible"
        :image-url="currentImageUrl"
        :file-id="currentImageUrl ? null : currentImageData"
        :service-name="currentImageUrl ? '' : serviceName"
        :image-name="`${altPrefix}${currentIndex + 1}`"
        @close="handleGalleryClose"
      />

      <!-- 多图导航条 -->
      <div v-if="fileIds.length > 1" class="gallery-nav-overlay">
        <div class="nav-button prev" :class="{ disabled: currentIndex === 0 }" @click="prevImage">
          <a-icon type="left" />
        </div>
        <div class="thumbnail-list">
          <div
            v-for="(fileData, index) in fileIds"
            :key="`thumb_${getFileKey(fileData)}_${index}`"
            class="thumbnail-item"
            :class="{ active: index === currentIndex }"
            @click="setCurrentIndex(index)"
          >
            <img
              v-if="urlsMap[index]"
              :src="urlsMap[index]"
              :alt="`缩略图${index + 1}`"
              class="nav-thumb-img"
            />
            <div v-else class="nav-thumb-placeholder">
              <a-icon type="picture" />
            </div>
          </div>
        </div>
        <div class="nav-button next" :class="{ disabled: currentIndex === fileIds.length - 1 }" @click="nextImage">
          <a-icon type="right" />
        </div>
        <span class="image-counter">{{ currentIndex + 1 }} / {{ fileIds.length }}</span>
      </div>
    </template>
  </div>
</template>

<script>
import ImagePreviewModal from '@vue2-client/base-client/components/common/ImagePreviewModal/ImagePreviewModal.vue'
import { createFileImageService } from '@vue2-client/utils/fileImageService'

export default {
  name: 'FileImageGroup',
  components: { ImagePreviewModal },
  props: {
    fileIds: { type: Array, default: () => [] },
    /** 服务名，如 'af-safecheck'，用于通过 fileId 加载图片 */
    serviceName: { type: String, default: '' },
    altPrefix: { type: String, default: '图片' },
    emptyText: { type: String, default: '暂无图片' },
    columns: { type: Number, default: 3, validator: v => v >= 1 && v <= 6 },
    imageSize: { type: [String, Number], default: 90 },
    gap: { type: [String, Number], default: 10 }
  },
  data () {
    return {
      galleryVisible: false,
      currentIndex: 0,
      urlsMap: {},
      loadingMap: {},
      errorMap: {}
    }
  },
  computed: {
    gridClass () {
      return `grid-columns-${this.columns}`
    },
    gridStyle () {
      return { gap: typeof this.gap === 'number' ? `${this.gap}px` : this.gap }
    },
    thumbStyle () {
      const size = typeof this.imageSize === 'number' ? `${this.imageSize}px` : this.imageSize
      return { width: size, height: size }
    },
    currentImageData () {
      return this.fileIds[this.currentIndex]
    },
    currentImageUrl () {
      const url = this.urlsMap[this.currentIndex]
      if (url) return url
      const data = this.currentImageData
      if (data && typeof data === 'object' && data.url) return data.url
      return ''
    }
  },
  watch: {
    fileIds: {
      handler () { this.loadAllThumbnails() },
      immediate: true
    }
  },
  methods: {
    getFileKey (fileData) {
      if (typeof fileData === 'object' && fileData !== null && fileData.id) return fileData.id
      return fileData
    },

    async loadAllThumbnails () {
      if (!this.fileIds || this.fileIds.length === 0) return
      this.urlsMap = {}
      this.loadingMap = {}
      this.errorMap = {}

      this.fileIds.forEach((_, index) => {
        this.$set(this.loadingMap, index, true)
      })

      await Promise.all(
        this.fileIds.map((fileData, index) => this.loadThumbnail(fileData, index))
      )
    },

    async loadThumbnail (fileData, index) {
      // 对象含直接 url 时免请求
      if (fileData && typeof fileData === 'object' && fileData.url) {
        this.$set(this.urlsMap, index, fileData.url)
        this.$set(this.loadingMap, index, false)
        return
      }
      if (!this.serviceName) {
        this.$set(this.loadingMap, index, false)
        this.$set(this.errorMap, index, true)
        return
      }
      try {
        const svc = createFileImageService({ serviceName: this.serviceName })
        const url = await svc.getImageUrl(fileData)
        this.$set(this.urlsMap, index, url)
        this.$set(this.loadingMap, index, false)
      } catch (e) {
        this.$set(this.loadingMap, index, false)
        this.$set(this.errorMap, index, true)
      }
    },

    handleGalleryClose () {
      this.galleryVisible = false
    },

    handleImageClick (index) {
      this.currentIndex = index
      this.galleryVisible = true
    },

    setCurrentIndex (index) {
      if (index >= 0 && index < this.fileIds.length) this.currentIndex = index
    },

    prevImage () {
      if (this.currentIndex > 0) this.currentIndex--
    },

    nextImage () {
      if (this.currentIndex < this.fileIds.length - 1) this.currentIndex++
    }
  }
}
</script>

<style lang="less" scoped>
.file-image-group { width: 100%; }

.image-grid {
  display: grid;
  &.grid-columns-1 { grid-template-columns: 1fr; }
  &.grid-columns-2 { grid-template-columns: repeat(2, 1fr); }
  &.grid-columns-3 { grid-template-columns: repeat(3, 1fr); }
  &.grid-columns-4 { grid-template-columns: repeat(4, 1fr); }
  &.grid-columns-5 { grid-template-columns: repeat(5, 1fr); }
  &.grid-columns-6 { grid-template-columns: repeat(6, 1fr); }
}

.file-image-thumb-wrapper {
  position: relative;
  border-radius: 8px;
  overflow: hidden;
  cursor: pointer;
  border: 1px solid #e5e7eb;
  background: #fafafa;
  transition: all 0.2s ease;
  display: flex;
  align-items: center;
  justify-content: center;

  &:hover {
    transform: translateY(-1px);
    box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
    .thumb-overlay { opacity: 1; }
  }
}

.thumb-img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
}

.thumb-loading,
.thumb-error {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 100%;
  height: 100%;
  color: #bfbfbf;
  font-size: 18px;
}

.thumb-overlay {
  position: absolute;
  top: 0; left: 0; right: 0; bottom: 0;
  background: rgba(0, 0, 0, 0.6);
  color: white;
  display: flex;
  align-items: center;
  justify-content: center;
  opacity: 0;
  transition: opacity 0.2s ease;
}

.empty-state {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 8px;
  height: 120px;
  color: #9ca3af;
  font-size: 12px;
  background: rgba(0, 0, 0, 0.02);
  border: 1px dashed #e5e7eb;
  border-radius: 8px;

  .anticon { font-size: 24px; color: #d1d5db; }
}

.gallery-nav-overlay {
  position: fixed;
  bottom: 100px;
  left: 50%;
  transform: translateX(-50%);
  z-index: 10001;
  display: flex;
  align-items: center;
  gap: 12px;
  padding: 12px 20px;
  background: rgba(0, 0, 0, 0.6);
  backdrop-filter: blur(8px);
  border-radius: 24px;
  border: 1px solid rgba(255, 255, 255, 0.15);
  box-shadow: 0 6px 16px rgba(0, 0, 0, 0.3);

  .image-counter {
    margin-left: 8px;
    font-size: 12px;
    color: rgba(255, 255, 255, 0.85);
    font-weight: 500;
  }
}

.nav-button {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 32px;
  height: 32px;
  border-radius: 50%;
  background: rgba(255, 255, 255, 0.15);
  border: 1px solid rgba(255, 255, 255, 0.2);
  color: #fff;
  cursor: pointer;
  transition: all 0.2s ease;

  &:hover:not(.disabled) {
    background: rgba(255, 255, 255, 0.25);
  }

  &.disabled { opacity: 0.4; cursor: not-allowed; }
}

.thumbnail-list {
  display: flex;
  gap: 8px;
  overflow-x: auto;
  padding: 4px;
  max-width: 400px;
}

.thumbnail-item {
  flex-shrink: 0;
  width: 48px;
  height: 48px;
  border-radius: 6px;
  overflow: hidden;
  cursor: pointer;
  border: 2px solid transparent;
  transition: border-color 0.2s ease;
  background: rgba(255, 255, 255, 0.1);

  &:hover { border-color: rgba(255, 255, 255, 0.4); }
  &.active { border-color: #1890ff; }
}

.nav-thumb-img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
}

.nav-thumb-placeholder {
  width: 100%;
  height: 100%;
  display: flex;
  align-items: center;
  justify-content: center;
  color: rgba(255, 255, 255, 0.4);
  font-size: 14px;
}
</style>
