<template>
  <div class="file-masonry-view">
    <div
      v-for="row in rows"
      :key="row.name"
      class="masonry-item"
      :class="{ selected: selectedKeys.includes(row.name), previewed: previewName === row.name }"
      @click="$emit('rowClick', row)"
    >
      <div class="masonry-checkbox" @click.stop>
        <input type="checkbox" :checked="selectedKeys.includes(row.name)" @change="$emit('toggleSelection', row.name)" />
      </div>
      <!-- 图片文件：自适应高度 -->
      <img
        v-if="isImageFile(row) && (row.thumbnail_url || row.file_url)"
        :src="row.thumbnail_url || row.file_url"
        :alt="row.file_name"
        loading="lazy"
        decoding="async"
        class="masonry-img"
      />
      <!-- 非图片文件：固定高度占位 -->
      <div v-else class="masonry-placeholder" :style="{ backgroundColor: getFileColor(row) + '12' }">
        <Icon :icon="getFileIcon(row)" :size="48" :style="{ color: getFileColor(row) }" />
        <span v-if="getFileBadge(row)" class="placeholder-badge" :style="{ color: getFileColor(row) }">{{ getFileBadge(row).label }}</span>
      </div>
      <!-- 文件信息叠加层 -->
      <div class="masonry-overlay">
        <div class="overlay-name">{{ row.file_name || row.name }}</div>
        <div v-if="row.file_size" class="overlay-size">{{ formatFileSize(row.file_size) }}</div>
      </div>
      <!-- 操作 -->
      <div class="masonry-actions" @click.stop>
        <slot name="actions" :row="row" />
      </div>
    </div>
  </div>
</template>

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

defineProps<{
  rows: any[]
  selectedKeys: string[]
  previewName: string
}>()

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

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

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 }> = {
  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' },
}

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>
/* CSS Columns 瀑布流：图片自然撑高，非图片固定高度 */
.file-masonry-view {
  columns: 4;
  column-gap: 12px;
}

@media (max-width: 1200px) { .file-masonry-view { columns: 3; } }
@media (max-width: 768px) { .file-masonry-view { columns: 2; } }

.masonry-item {
  break-inside: avoid;
  margin-bottom: 12px;
  border-radius: 6px;
  overflow: hidden;
  background: #fff;
  border: 1px solid #f0f0f0;
  cursor: pointer;
  transition: all 0.2s;
  position: relative;
}

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

.masonry-checkbox {
  position: absolute;
  top: 6px;
  right: 6px;
  z-index: 5;
  background: rgba(255,255,255,0.85);
  border-radius: 4px;
  padding: 2px;
}

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

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

.masonry-placeholder {
  height: 120px;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 8px;
}

.placeholder-badge {
  font-size: 10px;
  font-weight: 700;
  letter-spacing: 0.5px;
}

/* 叠加信息层 */
.masonry-overlay {
  position: absolute;
  bottom: 0;
  left: 0;
  right: 0;
  padding: 24px 8px 6px;
  background: linear-gradient(transparent, rgba(0,0,0,0.6));
  color: #fff;
  opacity: 0;
  transition: opacity 0.2s;
}

.masonry-item:hover .masonry-overlay { opacity: 1; }

.overlay-name {
  font-size: 12px;
  font-weight: 500;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.overlay-size {
  font-size: 10px;
  opacity: 0.8;
}

/* 操作 */
.masonry-actions {
  position: absolute;
  top: 6px;
  left: 6px;
  z-index: 5;
  display: flex;
  gap: 2px;
  opacity: 0;
  transition: opacity 0.15s;
}

.masonry-item:hover .masonry-actions { opacity: 1; }
</style>
