<template>
  <div class="file-card-view" :style="gridStyle">
    <div
      v-for="row in rows"
      :key="row.name"
      class="file-card"
      :class="{ selected: selectedKeys.includes(row.name), previewed: previewName === row.name }"
      @click="$emit('rowClick', row)"
    >
      <div class="card-checkbox" @click.stop>
        <input type="checkbox" :checked="selectedKeys.includes(row.name)" @change="$emit('toggleSelection', row.name)" />
      </div>
      <!-- 卡片图片区域 -->
      <div class="card-image-area">
        <!-- 图片文件：渲染缩略图 -->
        <img
          v-if="isImageFile(row) && row.thumbnail_url"
          :src="row.thumbnail_url"
          :alt="row.file_name"
          loading="lazy"
          decoding="async"
          class="card-img"
        />
        <!-- 图片文件无缩略图：尝试 file_url -->
        <img
          v-else-if="isImageFile(row) && row.file_url"
          :src="row.file_url"
          :alt="row.file_name"
          loading="lazy"
          decoding="async"
          class="card-img"
        />
        <!-- 非图片文件：文件类型图标占位 -->
        <div v-else class="card-image-placeholder" :style="{ backgroundColor: getFileColor(row) + '15' }">
          <Icon :icon="getFileIcon(row)" :size="40" :style="{ color: getFileColor(row) }" />
        </div>
        <!-- 文件类型色标 -->
        <span v-if="getFileBadge(row)" class="file-type-badge" :style="{ backgroundColor: getFileBadge(row).color }">
          {{ getFileBadge(row).label }}
        </span>
      </div>
      <!-- 卡片内容 -->
      <div class="card-content">
        <div class="card-title">{{ row.file_name || row.name }}</div>
        <div class="card-meta">
          <span v-if="row.file_size" class="meta-item">{{ formatFileSize(row.file_size) }}</span>
          <span v-if="row.file_type" class="meta-item meta-type">{{ row.file_type.toUpperCase() }}</span>
        </div>
      </div>
      <!-- 操作列 -->
      <div class="card-actions" @click.stop>
        <slot name="actions" :row="row" />
      </div>
    </div>
  </div>
</template>

<script setup lang="ts">
import { computed } from 'vue'
import { Icon } from '@iconify/vue'
import { t } from '@/shared/i18n'

const props = defineProps<{
  rows: any[]
  selectedKeys: string[]
  previewName: string
  cardSize: 'S' | 'M' | 'L'
}>()

defineEmits(['rowClick', 'toggleSelection'])

const IMAGE_EXTENSIONS = ['jpg', 'jpeg', 'png', 'gif', 'webp', 'svg', 'bmp', 'ico']

const sizeMap: Record<string, string> = { S: '140px', M: '200px', L: '280px' }

const gridStyle = computed(() => ({
  '--card-min-width': sizeMap[props.cardSize] || '200px',
}))

function isImageFile(row: any): boolean {
  return IMAGE_EXTENSIONS.includes((row.file_type || '').toLowerCase())
}

function getFileIcon(row: any): string {
  const ext = (row.file_type || '').toLowerCase()
  if (row.is_folder) return 'tabler:folder'
  if (IMAGE_EXTENSIONS.includes(ext)) return 'tabler:photo'
  if (['pdf'].includes(ext)) return 'tabler:file-type-pdf'
  if (['doc', 'docx'].includes(ext)) return 'tabler:file-type-doc'
  if (['xls', 'xlsx'].includes(ext)) return 'tabler:file-type-xls'
  if (['zip', 'rar', '7z', 'tar', 'gz'].includes(ext)) return 'tabler:file-zip'
  if (['mp4', 'avi', 'mov', 'mkv', 'webm'].includes(ext)) return 'tabler:file-type-video'
  if (['mp3', 'wav', 'flac', 'aac', 'ogg'].includes(ext)) return 'tabler:file-type-audio'
  return 'tabler:file'
}

function getFileColor(row: any): string {
  const ext = (row.file_type || '').toLowerCase()
  if (row.is_folder) return '#f59e0b'
  if (IMAGE_EXTENSIONS.includes(ext)) return '#10b981'
  if (['pdf'].includes(ext)) return '#ef4444'
  if (['doc', 'docx'].includes(ext)) return '#3b82f6'
  if (['xls', 'xlsx'].includes(ext)) return '#059669'
  if (['zip', 'rar', '7z'].includes(ext)) return '#8b5cf6'
  if (['mp4', 'avi', 'mov'].includes(ext)) return '#ec4899'
  if (['mp3', 'wav', 'flac'].includes(ext)) return '#f97316'
  return '#6b7280'
}

const BADGE_MAP: Record<string, { label: string; color: string }> = {
  jpg: { label: 'JPG', color: '#10b981' }, jpeg: { label: 'JPG', color: '#10b981' },
  png: { label: 'PNG', color: '#14b8a6' }, gif: { label: 'GIF', color: '#f59e0b' },
  webp: { label: 'WEBP', color: '#06b6d4' }, svg: { label: 'SVG', color: '#8b5cf6' },
  pdf: { label: 'PDF', color: '#ef4444' },
  doc: { label: 'DOC', color: '#3b82f6' }, docx: { label: 'DOC', color: '#3b82f6' },
  xls: { label: 'XLS', color: '#059669' }, xlsx: { label: 'XLS', color: '#059669' },
  zip: { label: 'ZIP', color: '#8b5cf6' }, rar: { label: 'RAR', color: '#8b5cf6' },
  mp4: { label: 'MP4', color: '#ec4899' }, mov: { label: 'MOV', color: '#ec4899' },
  mp3: { label: 'MP3', color: '#f97316' }, wav: { label: 'WAV', color: '#f97316' },
}

function getFileBadge(row: any): { label: string; color: string } | null {
  if (row.is_folder) return { label: t('Folder'), color: '#f59e0b' }
  return BADGE_MAP[(row.file_type || '').toLowerCase()] || null
}

function formatFileSize(bytes: number | string): string {
  const size = typeof bytes === 'string' ? parseInt(bytes, 10) : bytes
  if (isNaN(size) || size === 0) return '0 B'
  const units = ['B', 'KB', 'MB', 'GB', 'TB']
  const i = Math.floor(Math.log(size) / Math.log(1024))
  return (size / Math.pow(1024, i)).toFixed(i > 0 ? 1 : 0) + ' ' + units[i]
}
</script>

<style scoped>
.file-card-view {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(var(--card-min-width, 200px), 1fr));
  gap: 16px;
}

.file-card {
  background: #fff;
  border: 1px solid #f0f0f0;
  border-radius: 8px;
  overflow: hidden;
  cursor: pointer;
  transition: all 0.2s;
  position: relative;
  display: flex;
  flex-direction: column;
}

.file-card:hover { border-color: #d1d5db; box-shadow: 0 1px 4px rgba(0,0,0,0.06); }
.file-card.selected { background: #f0f9ff; border-color: #93c5fd; }
.file-card.previewed { background: #eff6ff; border-color: #3b82f6; }

.card-checkbox {
  position: absolute;
  top: 8px;
  right: 8px;
  z-index: 5;
}

.card-checkbox input { cursor: pointer; accent-color: #3b82f6; width: 16px; height: 16px; }

/* 图片区域 */
.card-image-area {
  width: 100%;
  aspect-ratio: 4 / 3;
  overflow: hidden;
  background: #f9fafb;
  position: relative;
  display: flex;
  align-items: center;
  justify-content: center;
}

.card-img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  transition: transform 0.2s;
}

.file-card:hover .card-img { transform: scale(1.03); }

.card-image-placeholder {
  width: 100%;
  height: 100%;
  display: flex;
  align-items: center;
  justify-content: center;
}

.file-type-badge {
  position: absolute;
  bottom: 6px;
  left: 6px;
  padding: 2px 8px;
  border-radius: 4px;
  font-size: 10px;
  font-weight: 700;
  color: #fff;
  letter-spacing: 0.5px;
  z-index: 3;
}

/* 卡片内容 */
.card-content {
  padding: 10px 12px;
  flex: 1;
  min-width: 0;
}

.card-title {
  font-size: 13px;
  font-weight: 500;
  color: #1f2937;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.card-meta {
  display: flex;
  align-items: center;
  gap: 8px;
  margin-top: 4px;
  font-size: 11px;
  color: #9ca3af;
}

.meta-type {
  background: #f3f4f6;
  padding: 1px 6px;
  border-radius: 3px;
  font-weight: 600;
}

/* 操作列 */
.card-actions {
  display: flex;
  align-items: center;
  justify-content: flex-end;
  padding: 0 10px 8px;
  gap: 2px;
  opacity: 0;
  transition: opacity 0.15s;
}

.file-card:hover .card-actions { opacity: 1; }
</style>
