<template>
  <div class="image-card-container">
    <el-empty v-if="!list.length" :description="$t('通用.暂无数据')" />
    <div v-else class="card-grid" :style="{ gridTemplateColumns: `repeat(${columnCount}, 1fr)` }">
      <div
        v-for="(item, index) in list"
        :key="index"
        class="card-item"
        :class="{ selected: selectedIds.includes(item.id) }"
        @click="toggleSelectFun(item)"
      >
        <div class="image-wrapper">
          <el-image
            :src="getImageSrcFun(item.id)"
            fit="contain"
            :loading="'lazy'"
            @load="imageLoadFun(item.id)"
            @error="imageErrorFun(item.id)"
          >
            <template #placeholder>
              <div class="image-loading">
                <el-icon class="is-loading"><Loading /></el-icon>
                <span>{{ $t('通用.加载中') }}</span>
              </div>
            </template>
            <template #error>
              <div v-if="isAutoRetrying(item.id)" class="image-loading">
                <el-icon class="is-loading"><Loading /></el-icon>
                <span>{{ $t('通用.加载中') }}</span>
              </div>
              <div v-else class="image-error">
                <el-icon class="error-icon"><WarningFilled /></el-icon>
                <span class="error-text">{{ $t('通用.加载失败请稍后再试') }}</span>
                <el-button
                  size="small"
                  type="primary"
                  :loading="retryingIds.has(item.id)"
                  @click.stop="retryLoadFun(item.id, true)"
                >
                  {{ $t('通用.重试') }}
                </el-button>
              </div>
            </template>
          </el-image>
          <div v-if="selectedIds.includes(item.id)" class="check-mark">
            <el-icon><Check /></el-icon>
          </div>
        </div>
        <div class="file-name" :title="item.originalName">
          {{ $t('通用.文件名') }}：{{ item.originalName }}
        </div>
        <div class="action-bar">
          <el-button size="small" type="primary" link @click.stop="emits('download', item)">
            {{ $t('通用.下载') }}
          </el-button>
          <el-button size="small" type="primary" link @click.stop="emits('preview', item)">
            {{ $t('通用.预览') }}
          </el-button>
          <el-button
            v-if="showDelete"
            size="small"
            type="danger"
            link
            @click.stop="showDeleteConfirmFun(item)"
          >
            {{ $t('通用.删除') }}
          </el-button>
        </div>
      </div>
    </div>
  </div>
</template>

<script setup lang="ts">
import { ref, reactive, watch } from 'vue';
import { ElMessageBox } from 'element-plus';
import { useI18n } from 'vue-i18n';
import { Check, WarningFilled, Loading } from '@element-plus/icons-vue';
import { FileUtil } from '@/utils/file';

const { t } = useI18n();

interface Props {
  list: any[];
  columnCount?: number;
  showDelete?: boolean;
}

const props = withDefaults(defineProps<Props>(), {
  list: () => [],
  columnCount: 4,
  showDelete: true,
});

const emits = defineEmits<{
  (e: 'download', item: any): void;
  (e: 'preview', item: any): void;
  (e: 'delete', item: any): void;
  (e: 'selectionChange', ids: string[]): void;
}>();

const selectedIds = ref<string[]>([]);
const retryTimestamps = reactive<Record<string, number>>({});
const retryingIds = ref<Set<string>>(new Set());
const retryCountMap = reactive<Record<string, number>>({});
const MAX_AUTO_RETRY = 3;

const showDeleteConfirmFun = (item: any) => {
  ElMessageBox.confirm(t('通用.确认删除吗'), t('通用.提示'), {
    confirmButtonText: t('通用.确定'),
    cancelButtonText: t('通用.取消'),
    type: 'warning',
  }).then(() => {
    emits('delete', item);
  }).catch(() => {});
};

const getImageSrcFun = (id: string) => {
  const baseUrl = FileUtil.getFilePreviewImgPathUrl(id);
  const timestamp = retryTimestamps[id];
  if (timestamp) {
    const separator = baseUrl.includes('?') ? '&' : '?';
    return `${baseUrl}${separator}_t=${timestamp}`;
  }
  return baseUrl;
};

const imageLoadFun = (id: string) => {
  retryingIds.value.delete(id);
  delete retryCountMap[id];
};

const isAutoRetrying = (id: string) => {
  const count = retryCountMap[id] || 0;
  return count < MAX_AUTO_RETRY;
};

const imageErrorFun = (id: string) => {
  retryingIds.value.delete(id);
  if (!retryCountMap[id]) {
    retryCountMap[id] = 0;
  }
  if (retryCountMap[id] < MAX_AUTO_RETRY) {
    retryCountMap[id]++;
    setTimeout(() => {
      retryLoadFun(id);
    }, 500);
  }
};

const retryLoadFun = (id: string, isManual = false) => {
  if (isManual) {
    retryCountMap[id] = 0;
  }
  retryingIds.value.add(id);
  retryTimestamps[id] = Date.now();
};

const toggleSelectFun = (item: any) => {
  const index = selectedIds.value.indexOf(item.id);
  if (index > -1) {
    selectedIds.value.splice(index, 1);
  } else {
    selectedIds.value.push(item.id);
  }
  emits('selectionChange', selectedIds.value);
};

const getSelectedIds = () => {
  return selectedIds.value;
};

const clearSelection = () => {
  selectedIds.value = [];
};

const reloadFailedImages = () => {
  Object.keys(retryCountMap).forEach((id) => {
    if (retryCountMap[id] >= MAX_AUTO_RETRY) {
      retryCountMap[id] = 0;
      retryTimestamps[id] = Date.now();
    }
  });
};

watch(
  () => props.list,
  () => {
    clearSelection();
  }
);

defineExpose({
  getSelectedIds,
  clearSelection,
  reloadFailedImages,
});
</script>

<style lang="scss" scoped>
.image-card-container {
  width: 100%;
  height: 100%;
  overflow-x: hidden;
  overflow-y: auto;

  .card-grid {
    display: grid;
    gap: 16px;
    min-width: 0;
  }

  .card-item {
    border-radius: 12px;
    border: 1px solid #f0f0f0;
    box-shadow: 0 4px 12px rgba(0, 0, 0, 0.05);
    padding: 8px;
    cursor: pointer;
    transition: all 0.3s;
    background: var(--el-bg-color);
    min-width: 0;

    &:hover {
      transform: translateY(-5px);
      box-shadow: 0 8px 24px rgba(0, 0, 0, 0.12);
    }

    &.selected {
      border-color: var(--el-color-primary);
      background: var(--el-color-primary-light-9);
    }

    .image-wrapper {
      position: relative;
      width: 100%;
      aspect-ratio: 4 / 3;
      display: flex;
      align-items: center;
      justify-content: center;
      background: var(--el-fill-color-light);
      border-radius: 4px;
      overflow: hidden;

      :deep(.el-image) {
        width: 100%;
        height: 100%;
      }

      .image-loading {
        display: flex;
        flex-direction: column;
        align-items: center;
        justify-content: center;
        gap: 8px;
        width: 100%;
        height: 100%;
        color: var(--el-text-color-secondary);
        font-size: 12px;

        .is-loading {
          font-size: 28px;
          animation: rotating 2s linear infinite;
        }
      }

      .image-error {
        display: flex;
        flex-direction: column;
        align-items: center;
        justify-content: center;
        gap: 8px;
        width: 100%;
        height: 100%;
        color: var(--el-text-color-secondary);

        .error-icon {
          font-size: 32px;
          color: var(--el-color-warning);
        }

        .error-text {
          font-size: 12px;
        }
      }

      .check-mark {
        position: absolute;
        top: 8px;
        right: 8px;
        width: 24px;
        height: 24px;
        background: var(--el-color-primary);
        border-radius: 50%;
        display: flex;
        align-items: center;
        justify-content: center;
        color: #fff;
      }
    }

    .file-name {
      margin-top: 8px;
      font-size: 13px;
      color: var(--el-text-color-regular);
      overflow: hidden;
      text-overflow: ellipsis;
      white-space: nowrap;
    }

    .action-bar {
      margin-top: 8px;
      display: flex;
      justify-content: center;
      flex-wrap: wrap;
      gap: 4px 8px;
      border-top: 1px solid var(--el-border-color-lighter);
      padding-top: 8px;
    }
  }
}
</style>
