<template>
  <div class="vm-upload-item">
    <template v-if="item.type === 'image' && !item.error && !imgBroken">
      <img
        class="vm-upload-item__media"
        :src="item.preload || item.url"
        alt=""
        @error="imgBroken = true"
      />
    </template>

    <template v-else-if="item.type === 'video' && videoSource">
      <img
        v-if="videoFrameSrc"
        class="vm-upload-item__media"
        :src="videoFrameSrc"
        alt=""
      />
      <video
        v-else-if="frameFailed"
        class="vm-upload-item__media"
        :src="videoSource"
        muted
        playsinline
        preload="metadata"
      />
      <span v-else class="vm-upload-item__loading" aria-hidden="true" />
      <span class="vm-upload-item__play" aria-hidden="true">
        <i class="ri-play-fill" />
      </span>
    </template>

    <template v-else>
      <div class="vm-upload-item__file">
        <i class="vm-upload-item__file-icon" :class="fileIcon" aria-hidden="true" />
        <span class="vm-upload-item__name">{{ item.name || item.url }}</span>
        <span v-if="item.error || imgBroken" class="vm-upload-item__error">
          {{ item.error || crudLabel('loadFailed') }}
        </span>
      </div>
    </template>

    <div
      v-if="showProgress"
      class="vm-upload-item__progress"
      aria-hidden="true"
    >
      <span>{{ item.progress }}%</span>
    </div>

    <span
      v-if="showTag"
      class="vm-upload-item__tag"
      :style="{ backgroundColor: tag.color }"
    >
      {{ tag.label }}
    </span>

    <div v-if="previewSrc" class="vm-upload-item__actions">
      <button
        type="button"
        :title="crudLabel('preview')"
        @click.stop="previewOpen = true"
      >
        <i class="ri-zoom-in-line" />
      </button>
      <button v-if="!disabled" type="button" :title="crudLabel('delete')" @click.stop="emit('remove')">
        <i class="ri-delete-bin-line" />
      </button>
    </div>

    <vm-preview-viewer
      v-if="previewSrc"
      embedded
      v-model:open="previewOpen"
      :src="previewSrc"
      :file-name="item.name || item.url"
      :resolve-download-url="resolveDownloadUrl"
    />
  </div>
</template>

<script setup lang="ts">
import { uploadRuleLabel } from '../../lib/upload'
import { crudLabel } from '../style'
import { ref, computed, watch } from 'vue'
import { useVideoFrame } from '../../lib/video-frame'
import { extname, getUploadRule } from '../../lib/upload'
import VmPreviewViewer from './vm-preview-viewer.vue'
import type { UploadItem } from '../../../../typings/admin/comm/upload'

defineOptions({ name: 'vm-upload-item' })

const props = withDefaults(
  defineProps<{
    item: UploadItem
    disabled?: boolean
    showTag?: boolean
    /** 私有文件：预览内点「下载」时先解析可访问短链 */
    resolveDownloadUrl?: (url: string) => Promise<string | undefined>
  }>(),
  {
    disabled: false,
    showTag: true,
  },
)

const emit = defineEmits<{ remove: [] }>()

const previewOpen = ref(false)
const imgBroken = ref(false)

const previewSrc = computed(() => props.item.preload || props.item.url || '')

/** 仅上传中显示；失败后隐藏，避免挡住预览/删除 */
const showProgress = computed(() => {
  if (props.item.error) return false
  const p = props.item.progress
  return p >= 0 && p < 100
})

const videoSource = computed(() => {
  if (props.item.type !== 'video') return ''
  return props.item.preload || props.item.url || ''
})

const { videoFrameSrc, frameFailed } = useVideoFrame(videoSource)

const tag = computed(() => {
  const rule = getUploadRule(props.item.type)
  return {
    color: rule.color,
    label: extname(props.item.name || props.item.url) || uploadRuleLabel(rule),
  }
})

const fileIcon = computed(() => {
  switch (props.item.type) {
    case 'pdf':
      return 'ri-file-pdf-line'
    case 'word':
      return 'ri-file-word-line'
    case 'excel':
      return 'ri-file-excel-line'
    case 'ppt':
      return 'ri-file-ppt-line'
    case 'audio':
      return 'ri-file-music-line'
    case 'video':
      return 'ri-file-video-line'
    case 'rar':
      return 'ri-file-zip-line'
    default:
      return 'ri-file-3-line'
  }
})

watch(
  () => props.item.url,
  () => {
    imgBroken.value = false
  },
)
</script>

<style lang="scss" scoped>
.vm-upload-item {
  position: relative;
  width: 100%;
  height: 100%;
  overflow: hidden;
  border-radius: 10px;
  border: 1px solid var(--border);
  background: var(--muted);
}

.vm-upload-item__media {
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
}

.vm-upload-item__loading {
  display: block;
  width: 100%;
  height: 100%;
  background: color-mix(in srgb, var(--muted) 70%, var(--foreground) 8%);
}

.vm-upload-item__play {
  position: absolute;
  inset: 0;
  display: grid;
  place-items: center;
  background: rgb(20 24 40 / 22%);
  color: #fff;
  pointer-events: none;

  i {
    font-size: 28px;
    line-height: 1;
  }
}

.vm-upload-item__file {
  display: grid;
  gap: 6px;
  height: 100%;
  padding: 10px;
  place-content: center;
  justify-items: center;
}

.vm-upload-item__file-icon {
  font-size: 40px;
  line-height: 1;
  color: var(--muted-foreground);
}

.vm-upload-item__name {
  max-width: 100%;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  font-size: 11px;
  color: var(--muted-foreground);
}

.vm-upload-item__error {
  font-size: 11px;
  color: var(--destructive);
}

.vm-upload-item__progress {
  position: absolute;
  inset: 0;
  z-index: 2;
  display: grid;
  place-items: center;
  background: rgba(0, 0, 0, 0.45);
  color: #fff;
  font-size: 22px;
  font-weight: 650;
  /* 进度只展示，不拦截预览/删除点击 */
  pointer-events: none;
}

.vm-upload-item__tag {
  position: absolute;
  top: 6px;
  left: 6px;
  z-index: 3;
  max-width: 72px;
  padding: 2px 6px;
  border-radius: 6px;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  font-size: 10px;
  color: #fff;
  text-transform: uppercase;
}

.vm-upload-item__actions {
  position: absolute;
  inset: 0;
  z-index: 4;
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 8px;
  opacity: 0;
  background: rgba(0, 0, 0, 0.45);
  transition: opacity 0.15s ease;

  button {
    display: inline-flex;
    width: 30px;
    height: 30px;
    align-items: center;
    justify-content: center;
    border: none;
    border-radius: 8px;
    background: rgba(255, 255, 255, 0.92);
    color: var(--foreground);
    cursor: pointer;

    &:hover {
      color: var(--brand);
    }
  }
}

.vm-upload-item:hover .vm-upload-item__actions {
  opacity: 1;
}
</style>
