<template>
  <div class="result-card" :class="{ 'clickable': loggedIn }" @click="loggedIn && openLink()">
    <!-- 封面图区域（左侧） -->
    <div class="card-cover">
      <!-- 后台静默加载资源图，成功后切换 -->
      <img v-if="showCover" :src="data.cover" :alt="data.title" @error="onCoverLoadError" loading="lazy" fetchpriority="low" />
      <!-- 默认先显示兜底图（自家服务器，秒加载） -->
      <img v-else-if="fallbackImage && !fallbackImgError" :src="fallbackImage" alt="cover" class="fallback-img" @error="onFallbackImgError" />
      <!-- 兜底图也没有就用渐变色占位 -->
      <div v-else class="cover-placeholder" :style="{ background: coverGradient }">
        <span class="placeholder-icon">
          <img v-if="cloudIcon.startsWith('data:') || cloudIcon.startsWith('http') || cloudIcon.startsWith('/')" :src="cloudIcon" style="width:36px;height:36px" />
          <span v-else>{{ cloudIcon }}</span>
        </span>
      </div>
      <span class="cover-tag" :style="{ background: CLOUD_COLORS[data.cloud_type] }">
        {{ CLOUD_LABELS[data.cloud_type] }}
      </span>
    </div>

    <!-- 右侧内容 -->
    <div class="card-body">
      <!-- 资源名称（已清洗前缀和【】）2行显示 -->
      <div class="card-title" :title="data.title">{{ cleanTitle }}</div>

      <!-- 更新时间 + 大小 -->
      <div class="card-time">
        <span>🕐 {{ relativeTime }}</span>
        <span v-if="data.file_size" class="meta-size">📦 {{ data.file_size }}</span>
      </div>

      <!-- 标签行（仅质量/格式/字幕类标签） -->
      <div v-if="displayTags.length > 0" class="card-tags">
        <span v-for="(tag, ti) in displayTags" :key="ti" class="tag" :class="'tag-' + tagClass(tag)">{{ tag }}</span>
      </div>

      <!-- 底部行：来源 + 操作按钮 -->
      <div class="card-bottom-row">
        <div class="bottom-left">
          <span v-if="sourceName" class="meta-source" :title="data.source">
            {{ sourceIcon }} {{ sourceName }}
          </span>
        </div>
        <div class="bottom-right">
          <button v-if="data.share_url && !loggedIn" class="action-btn get-link-btn" @click.stop="handleSave">
            🔗 获取分享链接
          </button>
          <button v-if="data.share_url && loggedIn" class="action-btn open-link-btn" @click.stop="openLink">
            🔗 打开链接
          </button>
        </div>
      </div>
    </div>
  </div>
</template>

<script setup lang="ts">
import { computed, ref, onMounted, onUnmounted } from 'vue'
import { ElMessage } from 'element-plus'
import { CLOUD_LABELS, CLOUD_ICONS, CLOUD_COLORS } from '../types'
import type { SearchResult } from '../types'

const props = defineProps<{
  data: SearchResult
  fallbackTags?: string[]
  fallbackImage?: string
  loggedIn?: boolean
  cloudTypeMap?: Record<string, { label: string; icon: string }>
}>()

const emit = defineEmits<{
  save: [data: SearchResult]
}>()

const PRELOAD_TIMEOUT_MS = 10000 // 资源图静默加载超时（10秒后放弃）

const showCover = ref(false)       // 是否切换显示资源图（默认先显示兜底）
const fallbackImgError = ref(false) // 兜底图加载失败
const coverLoading = ref(false)     // 资源图是否正在后台尝试
let preloadTimer: ReturnType<typeof setTimeout> | null = null

onMounted(() => {
  // 后台静默预加载资源图
  if (props.data.cover && !showCover.value) {
    coverLoading.value = true
    const img = new Image()
    let resolved = false

    preloadTimer = setTimeout(() => {
      // 超时未完成 -> 放弃，继续显示兜底图
      if (!resolved) {
        resolved = true
        coverLoading.value = false
      }
    }, PRELOAD_TIMEOUT_MS)

    img.onload = () => {
      if (!resolved) {
        resolved = true
        showCover.value = true
        coverLoading.value = false
        if (preloadTimer) clearTimeout(preloadTimer)
      }
    }

    img.onerror = () => {
      if (!resolved) {
        resolved = true
        coverLoading.value = false
        if (preloadTimer) clearTimeout(preloadTimer)
      }
    }

    img.src = props.data.cover
  }
})

onUnmounted(() => {
  if (preloadTimer) clearTimeout(preloadTimer)
})

// 极意外情况：showCover 后图片加载失败 -> 回退到兜底图
function onCoverLoadError() {
  showCover.value = false
  // 注意：此时 fallbackImage 可能已经加载过，浏览器有缓存会直接显示
}

function onFallbackImgError() { fallbackImgError.value = true }

// 网盘图标 — 优先使用 prop 中的 API 数据，fallback emoji
const cloudIcon = computed(() => {
  const icon = props.cloudTypeMap?.[props.data.cloud_type]?.icon
  return icon || CLOUD_ICONS[props.data.cloud_type] || '📁'
})

// 封面渐变色（无图时）
const coverGradient = computed(() => {
  const gradients: Record<string, string> = {
    quark: 'linear-gradient(135deg, #e8f5e9, #c8e6c9)',
    baidu: 'linear-gradient(135deg, #e3f2fd, #bbdefb)',
    aliyun: 'linear-gradient(135deg, #fff3e0, #ffe0b2)',
    '115': 'linear-gradient(135deg, #f3e5f5, #e1bee7)',
    xunlei: 'linear-gradient(135deg, #e8f5e9, #a5d6a7)',
    magnet: 'linear-gradient(135deg, #e8eaf6, #c5cae9)',
  }
  return gradients[props.data.cloud_type] || 'linear-gradient(135deg, #f5f5f5, #e0e0e0)'
})

// ===== 时间格式化 =====
function formatRelativeTime(dateStr?: string): string {
  if (!dateStr) return ''
  const now = Date.now()
  const date = new Date(dateStr)
  if (isNaN(date.getTime())) return dateStr.slice(0, 10)
  const diffMs = now - date.getTime()
  if (diffMs < 0) return dateStr.slice(0, 10)
  const secs = Math.floor(diffMs / 1000)
  if (secs < 60) return '刚刚'
  const mins = Math.floor(secs / 60)
  if (mins < 60) return `${mins} 分钟前`
  const hours = Math.floor(mins / 60)
  if (hours < 24) return `${hours} 小时前`
  const days = Math.floor(hours / 24)
  if (days < 30) return `${days} 天前`
  if (days < 365) return `${Math.floor(days / 30)} 个月前`
  return `${Math.floor(days / 365)} 年前`
}

const relativeTime = computed(() => {
  return formatRelativeTime(props.data.update_time || props.data.datetime)
})

// ===== 来源解析 =====
const sourceName = computed(() => {
  const src = props.data.source || ''
  if (!src) return ''
  if (src.startsWith('tg:')) return '@' + src.slice(3)
  if (src.startsWith('plugin:')) return src.slice(7)
  return src
})

const sourceIcon = computed(() => {
  const src = props.data.source || ''
  if (src.startsWith('tg:')) return '📢'
  if (src.startsWith('plugin:')) return '🔌'
  return '📎'
})

// ===== 标题清洗 =====
// 移除各类前缀： [夸克网盘]、【#电影名称：】等
const CLEAN_PREFIXES = [
  /^\[夸克网盘\][:：]?\s*/,
  /^【#电影名称：】\s*/,
  /^【#电影名称[:：]】\s*/,
  /^【[^】]*[网盘|分享|电影|下载|资源]】[:：]?\s*/,
  /^\[[^\]]*[网盘|分享|电影|下载|资源]\]\s*/,
  /^[#＃]电影名称[:：]?\s*/,
  /^[#＃]资源名称[:：]?\s*/,
  /^[#＃]标题[:：]?\s*/,
  /^【[^】]*资源名称[^】]*】\s*/,
  /^【影片名称】\s*/,
  /^【资源名称】\s*/,
  /^【标题】\s*/,
]

const cleanTitle = computed(() => {
  let title = props.data.title || ''
  // 1. 去除【】内的通用前缀类标识
  for (const pat of CLEAN_PREFIXES) {
    title = title.replace(pat, '')
  }
  // 2. 去除剩余的【xxx】内容（保留内容作为标签，标题只留干净部分）
  title = title.replace(/【[^】]+】/g, '').trim()
  return title || props.data.title
})

// ===== 标签 =====
const QUALITY_TAG_SET = new Set([
  '4K', '1080P', '2160P', '720P', '480P',
  'HDR', 'HDR10', 'HDR10+', 'DV', '杜比视界', '杜比全景声',
  '高码率', 'BluRay', 'REMUX', 'HEVC', 'x264', 'x265', 'AVC',
  '内封简繁英字幕', '内嵌中英字幕', '内封简繁', '内嵌字幕',
  '字幕', '中文字幕', '简繁字幕', '中英字幕', '内封字幕',
  '臻彩', '高清', 'WEB-DL', 'WEBRip', '蓝光',
])

const QUALITY_PATTERNS = [
  /\b(4K)\b/, /\b(1080[Pp])\b/, /\b(2160[Pp])\b/, /\b(720[Pp])\b/,
  /\b(HDR10?\+?)\b/i, /\b(DV)\b/i,
  /\b(BluRay|蓝光)\b/i, /\b(REMUX)\b/i, /\b(HEVC)\b/i,
  /\b(x264)\b/i, /\b(x265)\b/i, /\b(WEB-DL)\b/i, /\b(WEBRip)\b/i,
]

const displayTags = computed(() => {
  const title = props.data.title || ''
  const tags: string[] = []

  // 1. 从【xxx】提取内容，只保留质量/格式/字幕类标签
  const bracketMatches = title.matchAll(/【([^】]+)】/g)
  for (const m of bracketMatches) {
    const inner = m[1]
    const parts = inner.split(/[.·、,,\/\\|]/)
    for (const p of parts) {
      const trimmed = p.trim()
      if (trimmed && QUALITY_TAG_SET.has(trimmed) && !tags.includes(trimmed)) {
        tags.push(trimmed)
      }
    }
  }

  // 2. 额外从标题提取分辨率/编码标签
  for (const pat of QUALITY_PATTERNS) {
    const m = title.match(pat)
    if (m) {
      const found = m[1]
      if (!tags.includes(found)) tags.push(found)
    }
  }

  // 3. 从标题全文找包含的关键词
  const fullTextKeywords = ['杜比视界', '杜比全景声', '高码率', '内封简繁英字幕', '内嵌中英字幕', '内封简繁', '内嵌字幕', '中文字幕', '简繁字幕', '中英字幕', '内封字幕', '臻彩']
  for (const kw of fullTextKeywords) {
    if (title.includes(kw) && !tags.includes(kw)) {
      tags.push(kw)
    }
  }

  if (tags.length === 0 && props.fallbackTags && props.fallbackTags.length > 0) {
    return props.fallbackTags.slice(0, 6)
  }

  return tags.slice(0, 10)
})

function tagClass(tag: string): string {
  const quality = ['4K', '1080P', '2160P', '720P', '480P', 'HDR', 'HDR10', 'HDR10+', 'DV', '杜比视界', 'BluRay', 'REMUX', 'HEVC', 'x264', 'x265', '臻彩', '高清', 'WEB-DL', 'WEBRip']
  if (quality.includes(tag)) return 'quality'
  if (tag.includes('字幕') || tag === '杜比全景声' || tag === '高码率') return 'subtitle'
  return 'default'
}

// ===== 交互行为 =====
function handleSave() {
  emit('save', props.data)
}

function openLink() {
  if (props.data.share_url) {
    window.open(props.data.share_url, '_blank')
  }
}
</script>

<style scoped>
.result-card {
  display: flex;
  background: #fff;
  border-radius: 10px;
  padding: 12px;
  gap: 14px;
  border: 1px solid #ebeef5;
  transition: all 0.2s ease;
  content-visibility: auto;
  contain-intrinsic-size: 130px 120px;
  min-width: 0;
}
.result-card:hover {
  border-color: #c0c4cc;
  box-shadow: 0 2px 12px rgba(0, 0, 0, 0.06);
}
.result-card.clickable {
  cursor: pointer;
}
.result-card.clickable:hover {
  border-color: #409eff;
  box-shadow: 0 2px 12px rgba(64, 158, 255, 0.12);
}

/* ---- 封面（左侧，与右侧等高） ---- */
.card-cover {
  position: relative;
  flex: 0 0 100px;
  max-width: 130px;
  border-radius: 8px;
  overflow: hidden;
  background: #f0f2f5;
  display: flex;
  align-items: center;
  justify-content: center;
  align-self: stretch;
  min-height: 100%;
}
.card-cover img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  transition: transform 0.3s ease;
  position: absolute;
  top: 0;
  left: 0;
}
.card-cover img.fallback-img {
  object-fit: contain;
  background: #f0f2f5;
  loading: eager;
}
.result-card:hover .card-cover img {
  transform: scale(1.05);
}
.cover-placeholder {
  width: 100%;
  height: 100%;
  display: flex;
  align-items: center;
  justify-content: center;
  position: absolute;
  top: 0;
  left: 0;
}
.placeholder-icon {
  font-size: 30px;
  opacity: 0.5;
  filter: grayscale(0.2);
}
.cover-tag {
  position: absolute;
  bottom: 5px;
  left: 5px;
  padding: 1px 7px;
  border-radius: 4px;
  color: #fff;
  font-size: 11px;
  font-weight: 600;
  line-height: 1.5;
  letter-spacing: 0.3px;
  backdrop-filter: blur(2px);
  z-index: 1;
}

/* ---- 右侧内容 ---- */
.card-body {
  flex: 1;
  min-width: 0;
  display: flex;
  flex-direction: column;
  gap: 5px;
}

/* 资源名称 */
.card-title {
  font-size: 15px;
  font-weight: 700;
  color: #1a1a2e;
  line-height: 1.4;
  display: -webkit-box;
  -webkit-line-clamp: 2;
  -webkit-box-orient: vertical;
  overflow: hidden;
}

/* 更新时间 */
.card-time {
  font-size: 12px;
  color: #909399;
  display: flex;
  align-items: center;
  gap: 10px;
}
.meta-size {
  color: #67c23a;
  white-space: nowrap;
  font-size: 11px;
}

/* ---- 标签 ---- */
.card-tags {
  display: flex;
  flex-wrap: wrap;
  gap: 4px;
}
.tag {
  display: inline-block;
  padding: 1px 7px;
  border-radius: 4px;
  font-size: 11px;
  line-height: 1.8;
  white-space: nowrap;
  transition: opacity 0.2s;
}
.tag-quality {
  background: #fef0f0;
  color: #e74c3c;
}
.tag-subtitle {
  background: #f0f9eb;
  color: #67c23a;
}
.tag-default {
  background: #ecf5ff;
  color: #409eff;
}

/* ---- 底部行：来源 + 操作 ---- */
.card-bottom-row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 8px;
  margin-top: auto;
}
.bottom-left {
  display: flex;
  align-items: center;
  gap: 6px;
  min-width: 0;
}
.bottom-right {
  display: flex;
  align-items: center;
  gap: 6px;
  flex-shrink: 0;
}
.meta-source {
  color: #909399;
  background: #f4f4f5;
  padding: 2px 8px;
  border-radius: 4px;
  font-size: 11px;
  font-weight: 600;
  white-space: nowrap;
  max-width: 140px;
  overflow: hidden;
  text-overflow: ellipsis;
}
.action-btn {
  padding: 5px 12px;
  border: none;
  border-radius: 6px;
  cursor: pointer;
  font-size: 13px;
  font-weight: 600;
  transition: all 0.2s;
  white-space: nowrap;
  display: inline-flex;
  align-items: center;
  gap: 3px;
}
.get-link-btn {
  background: var(--primary-color);
  color: #fff;
}
.get-link-btn:hover {
  background: var(--primary-dark);
  transform: scale(1.05);
}
.open-link-btn {
  background: #67c23a;
  color: #fff;
}
.open-link-btn:hover {
  background: #5daf34;
  transform: scale(1.05);
}

/* ===== 响应式 ===== */
@media (max-width: 640px) {
  .result-card {
    flex-direction: column;
    gap: 10px;
  }
  .card-cover {
    width: 100%;
    height: 160px;
    align-self: auto;
  }
  .card-cover img {
    position: static;
    height: 160px;
  }
  .card-cover img.fallback-img {
    position: static;
  }
  .cover-placeholder {
    position: static;
  }
  .card-bottom-row {
    flex-wrap: wrap;
  }
}
</style>
