<script setup>
import { computed, ref, onMounted, onUnmounted, nextTick, watch } from "vue";
import { useNamespace } from "@yh-ui/hooks";
import { useComponentTheme } from "@yh-ui/theme";
import { aiFileCardProps, aiFileCardEmits } from "./ai-file-card";
import { YhIcon } from "../../icon";
import { YhSpin } from "../../spin";
import { YhImageViewer } from "../../image";
import { YhTooltip } from "../../tooltip";
defineOptions({
  name: "YhAiFileCard"
});
const props = defineProps(aiFileCardProps);
const emit = defineEmits(aiFileCardEmits);
const ns = useNamespace("ai-file-card");
const imageViewerVisible = ref(false);
const { themeStyle } = useComponentTheme(
  "ai-file-card",
  computed(() => props.themeOverrides)
);
const formatFileSize = (bytes) => {
  if (!bytes) return "0 B";
  const units = ["B", "KB", "MB", "GB", "TB"];
  let unitIndex = 0;
  let size = bytes;
  while (size >= 1024 && unitIndex < units.length - 1) {
    size /= 1024;
    unitIndex++;
  }
  return `${size.toFixed(1)} ${units[unitIndex]}`;
};
const iconMap = {
  default: "document",
  excel: "file-excel",
  image: "image",
  markdown: "document",
  pdf: "file-pdf",
  ppt: "document",
  word: "file-word",
  zip: "folder",
  video: "file-video",
  audio: "file-audio",
  java: "document",
  javascript: "document",
  python: "document",
  txt: "file-txt"
};
const fileIcon = computed(() => {
  if (props.icon && iconMap[props.icon]) {
    return iconMap[props.icon];
  }
  if (props.type === "image") return "image";
  if (props.type === "video") return "file-video";
  if (props.type === "audio") return "file-audio";
  return iconMap.default;
});
const showImagePreview = computed(() => {
  return props.type === "image" && props.src;
});
const showVideoPreview = computed(() => props.type === "video");
const showAudioPreview = computed(() => props.type === "audio");
const isHorizontalAudio = computed(() => props.type === "audio" && !!props.src);
const audioThumbIconSize = computed(() => {
  if (props.size === "small") return 18;
  if (props.size === "large") return 32;
  return 24;
});
const nameRef = ref(null);
const showNameTooltip = ref(false);
const updateNameTooltip = () => {
  const el = nameRef.value;
  if (!el) return;
  showNameTooltip.value = el.scrollWidth > el.clientWidth + 1;
};
const scheduleUpdate = () => {
  nextTick(() => {
    requestAnimationFrame(() => {
      requestAnimationFrame(updateNameTooltip);
    });
  });
};
let resizeObserver = null;
onMounted(() => {
  scheduleUpdate();
  const el = nameRef.value;
  if (el && typeof ResizeObserver !== "undefined") {
    resizeObserver = new ResizeObserver(scheduleUpdate);
    resizeObserver.observe(el);
  }
});
onUnmounted(() => {
  if (resizeObserver && nameRef.value) {
    resizeObserver.disconnect();
    resizeObserver = null;
  }
});
watch(() => [props.name, props.size], scheduleUpdate);
const sizeClass = computed(() => {
  return ns.m(props.size || "default");
});
const handleClick = () => {
  if (!props.loading) {
    if (showImagePreview.value) {
      imageViewerVisible.value = true;
    }
    emit("click");
  }
};
</script>

<template>
  <div
    :class="[ns.b(), sizeClass, isHorizontalAudio && ns.is('horizontal-audio')]"
    :style="themeStyle"
    @click="handleClick"
  >
    <!-- 图片类型：加载时显示模糊图，加载完成后过渡为清晰 -->
    <template v-if="showImagePreview">
      <div :class="[ns.e('image-wrapper'), ns.is('image-loading', loading)]">
        <img :src="src" :alt="name" :class="ns.e('image')" v-bind="imageProps" />
        <div v-if="loading" :class="ns.e('image-loading-overlay')">
          <YhSpin />
        </div>
        <!-- 遮罩 -->
        <div v-if="mask" :class="ns.e('mask')">
          <span>{{ mask }}</span>
        </div>
      </div>
    </template>

    <!-- 视频类型：与 Ant Design X 一致，使用原生 <video> 可直接播放；有 src 时展示播放器 -->
    <template v-else-if="showVideoPreview">
      <div :class="ns.e('image-wrapper')">
        <video
          v-if="src"
          :src="src"
          :class="ns.e('media-video')"
          controls
          preload="metadata"
          playsinline
          v-bind="videoProps"
        />
        <div v-else :class="[ns.e('media-placeholder'), ns.e('media-placeholder--video')]">
          <YhIcon :name="fileIcon" :size="size === 'small' ? 32 : size === 'large' ? 64 : 48" />
        </div>
        <div v-if="loading" :class="ns.e('image-loading-overlay')">
          <YhSpin />
        </div>
        <div v-if="mask" :class="ns.e('mask')">
          <span>{{ mask }}</span>
        </div>
      </div>
      <div :class="ns.e('info')">
        <div :class="ns.e('name-wrap')">
          <YhTooltip
            :content="name"
            placement="bottom"
            :popper-class="ns.e('name-tooltip')"
            :disabled="!showNameTooltip"
          >
            <div ref="nameRef" :class="ns.e('name')">
              {{ name }}
            </div>
          </YhTooltip>
        </div>
        <div v-if="byte !== void 0" :class="ns.e('size')">
          {{ formatFileSize(byte) }}
        </div>
        <div v-if="description" :class="ns.e('description')">
          {{ description }}
        </div>
      </div>
    </template>

    <!-- 音频类型：有 src 时使用横向布局（左图标 + 右内容 + 播放条），无 src 时方形占位卡片 -->
    <template v-else-if="showAudioPreview">
      <!-- 有 src：纵向布局（顶部文件信息行 + 底部全宽播放器） -->
      <template v-if="src">
        <div :class="ns.e('audio-header')">
          <div :class="ns.e('audio-thumb')">
            <YhIcon :name="fileIcon" :size="audioThumbIconSize" />
          </div>
          <div :class="ns.e('audio-meta')">
            <div :class="ns.e('name-wrap')">
              <YhTooltip
                :content="name"
                placement="bottom"
                :popper-class="ns.e('name-tooltip')"
                :disabled="!showNameTooltip"
              >
                <div ref="nameRef" :class="ns.e('name')">
                  {{ name }}
                </div>
              </YhTooltip>
            </div>
            <div v-if="byte !== void 0" :class="ns.e('size')">
              {{ formatFileSize(byte) }}
            </div>
          </div>
        </div>
        <audio :src="src" :class="ns.e('media-audio')" controls v-bind="audioProps" />
        <div v-if="loading" :class="ns.e('image-loading-overlay')">
          <YhSpin />
        </div>
      </template>
      <!-- 无 src：方形占位卡片（与之前一致） -->
      <template v-else>
        <div :class="ns.e('image-wrapper')">
          <div :class="[ns.e('media-placeholder'), ns.e('media-placeholder--audio')]">
            <YhIcon :name="fileIcon" :size="size === 'small' ? 32 : size === 'large' ? 64 : 48" />
          </div>
          <div v-if="loading" :class="ns.e('image-loading-overlay')">
            <YhSpin />
          </div>
          <div v-if="mask" :class="ns.e('mask')">
            <span>{{ mask }}</span>
          </div>
        </div>
        <div :class="ns.e('info')">
          <div :class="ns.e('name-wrap')">
            <YhTooltip
              :content="name"
              placement="bottom"
              :popper-class="ns.e('name-tooltip')"
              :disabled="!showNameTooltip"
            >
              <div ref="nameRef" :class="ns.e('name')">
                {{ name }}
              </div>
            </YhTooltip>
          </div>
          <div v-if="byte !== void 0" :class="ns.e('size')">
            {{ formatFileSize(byte) }}
          </div>
          <div v-if="description" :class="ns.e('description')">
            {{ description }}
          </div>
        </div>
      </template>
    </template>

    <!-- 文件类型 -->
    <template v-else>
      <div :class="ns.e('icon-wrapper')">
        <!-- 加载状态 -->
        <YhSpin v-if="loading" />
        <!-- 文件图标 -->
        <YhIcon
          v-else
          :name="fileIcon"
          :size="size === 'small' ? 32 : size === 'large' ? 64 : 48"
        />
      </div>

      <div :class="ns.e('info')">
        <div :class="ns.e('name-wrap')">
          <YhTooltip
            :content="name"
            placement="bottom"
            :popper-class="ns.e('name-tooltip')"
            :disabled="!showNameTooltip"
          >
            <div ref="nameRef" :class="ns.e('name')">
              {{ name }}
            </div>
          </YhTooltip>
        </div>
        <div v-if="byte !== void 0" :class="ns.e('size')">
          {{ formatFileSize(byte) }}
        </div>
        <div v-if="description" :class="ns.e('description')">
          {{ description }}
        </div>
      </div>
    </template>

    <!-- 遮罩层（非图片类型） -->
    <div v-if="mask && !showImagePreview" :class="ns.e('file-mask')">
      <span>{{ mask }}</span>
    </div>

    <!-- 扩展插槽（用于 AiAttachments 传入的删除按钮、进度条等） -->
    <div :class="ns.e('actions')">
      <slot />
    </div>
  </div>

  <!-- 图片预览 -->
  <YhImageViewer
    v-if="showImagePreview && imageViewerVisible"
    :url-list="[src || '']"
    @close="imageViewerVisible = false"
  />
</template>

<style>
@charset "UTF-8";
/**
 * YH-UI Sass Variables
 * 原具体的 CSS 变量输出规则 (:root, html.dark 等) 已移至 root.scss，以防止各组件样式编译时产生重复的全局变量 CSS 冗余。
 */
.yh-ai-file-card {
  --yh-ai-file-card-bg-color: var(--yh-bg-color, #fff);
  --yh-ai-file-card-border-color: var(--yh-border-color, #dcdfe6);
  --yh-ai-file-card-text-color: var(--yh-text-color, #303133);
  --yh-ai-file-card-text-secondary-color: var(--yh-text-color-secondary, #909399);
  --yh-ai-file-card-hover-bg-color: var(--yh-fill-color-light, #f5f7fa);
  --yh-ai-file-card-shadow: var(--yh-box-shadow, 0 2px 12px 0 rgba(0, 0, 0, 0.1));
  position: relative;
  display: inline-flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  padding: 16px;
  background: var(--yh-ai-file-card-bg-color);
  border: 1px solid var(--yh-ai-file-card-border-color);
  border-radius: 8px;
  cursor: pointer;
  transition: all 0.3s ease;
  box-sizing: border-box;
}
.yh-ai-file-card:hover {
  background: var(--yh-ai-file-card-hover-bg-color);
  box-shadow: var(--yh-ai-file-card-shadow);
}
.yh-ai-file-card--small {
  padding: 8px;
  border-radius: 4px;
  min-width: 80px;
}
.yh-ai-file-card--small .yh-ai-file-card__icon-wrapper {
  width: 40px;
  height: 40px;
}
.yh-ai-file-card--small .yh-ai-file-card__name {
  font-size: 12px;
  max-width: 64px;
}
.yh-ai-file-card--small .yh-ai-file-card__size {
  font-size: 10px;
}
.yh-ai-file-card--large {
  padding: 24px;
  border-radius: 12px;
  min-width: 180px;
}
.yh-ai-file-card--large .yh-ai-file-card__icon-wrapper {
  width: 80px;
  height: 80px;
}
.yh-ai-file-card--large .yh-ai-file-card__name {
  font-size: 16px;
  max-width: 160px;
}
.yh-ai-file-card--large .yh-ai-file-card__size {
  font-size: 14px;
}
.yh-ai-file-card--default {
  min-width: 120px;
}
.yh-ai-file-card--default .yh-ai-file-card__icon-wrapper {
  width: 56px;
  height: 56px;
}
.yh-ai-file-card--default .yh-ai-file-card__name {
  font-size: 14px;
  max-width: 100px;
}
.yh-ai-file-card--default .yh-ai-file-card__size {
  font-size: 12px;
}
.yh-ai-file-card__icon-wrapper {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 56px;
  height: 56px;
  margin-bottom: 8px;
  color: var(--yh-color-primary, #409eff);
}
.yh-ai-file-card__info {
  display: flex;
  flex-direction: column;
  align-items: stretch;
  gap: 4px;
  overflow: hidden;
  min-width: 0;
  width: 100%;
}
.yh-ai-file-card__name-wrap {
  width: 100%;
  min-width: 0;
  overflow: hidden;
}
.yh-ai-file-card__name-wrap .yh-tooltip {
  display: block;
  width: 100%;
  min-width: 0;
  overflow: hidden;
}
.yh-ai-file-card__name {
  font-size: 14px;
  line-height: 1.5;
  color: var(--yh-ai-file-card-text-color);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  text-align: center;
  max-width: 100%;
  width: 100%;
  min-width: 0;
  margin: 0 auto;
}
.yh-ai-file-card__size {
  font-size: 12px;
  color: var(--yh-ai-file-card-text-secondary-color);
  text-align: center;
  width: 100%;
  margin: 0 auto;
}
.yh-ai-file-card__description {
  font-size: 12px;
  color: var(--yh-ai-file-card-text-secondary-color);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  text-align: center;
  max-width: 150px;
  margin: 0 auto;
}
.yh-ai-file-card__image-wrapper {
  position: relative;
  width: 100%;
  flex: 1;
  min-height: 0;
  aspect-ratio: 1;
  display: flex;
  align-items: center;
  justify-content: center;
  overflow: hidden;
  border-radius: 4px;
  margin-bottom: 8px;
}
.yh-ai-file-card__image-wrapper.is-image-loading .yh-ai-file-card__image {
  filter: blur(8px);
  opacity: 0.7;
}
.yh-ai-file-card__image-wrapper .yh-ai-file-card__image {
  transition: filter 0.5s ease, opacity 0.5s ease;
}
.yh-ai-file-card__media-video {
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
  border-radius: 4px;
}
.yh-ai-file-card__media-audio {
  width: 100%;
  max-width: 100%;
  min-height: 40px;
  height: auto;
  display: block;
  border-radius: 4px;
  box-sizing: border-box;
}
.yh-ai-file-card.is-horizontal-audio {
  flex-direction: column;
  align-items: stretch;
  gap: 8px;
  padding: 10px 12px;
  min-width: 260px;
  cursor: default;
}
.yh-ai-file-card.is-horizontal-audio.yh-ai-file-card--small {
  gap: 6px;
  padding: 8px 10px;
  min-width: 220px;
}
.yh-ai-file-card.is-horizontal-audio.yh-ai-file-card--large {
  gap: 10px;
  padding: 16px;
  min-width: 320px;
}
.yh-ai-file-card__audio-header {
  display: flex;
  flex-direction: row;
  align-items: center;
  gap: 8px;
}
.yh-ai-file-card__audio-thumb {
  flex-shrink: 0;
  width: 36px;
  height: 36px;
  border-radius: 8px;
  display: flex;
  align-items: center;
  justify-content: center;
  background: linear-gradient(135deg, var(--yh-color-primary-light-9, #ecf5ff) 0%, var(--yh-color-primary-light-7, #c6e2ff) 100%);
  color: var(--yh-color-primary, #409eff);
}
.yh-ai-file-card--small .yh-ai-file-card__audio-thumb {
  width: 28px;
  height: 28px;
  border-radius: 6px;
}
.yh-ai-file-card--large .yh-ai-file-card__audio-thumb {
  width: 44px;
  height: 44px;
  border-radius: 10px;
}
.yh-ai-file-card__audio-meta {
  flex: 1;
  min-width: 0;
  display: flex;
  flex-direction: column;
  gap: 2px;
}
.yh-ai-file-card__audio-meta .yh-ai-file-card__name-wrap {
  width: 100%;
  min-width: 0;
}
.yh-ai-file-card__audio-meta .yh-ai-file-card__name {
  font-size: 13px;
  font-weight: 500;
  text-align: left;
  max-width: 100%;
  margin: 0;
}
.yh-ai-file-card__audio-meta .yh-ai-file-card__size {
  font-size: 11px;
  text-align: left;
  margin: 0;
}
.yh-ai-file-card__media-placeholder {
  width: 100%;
  height: 100%;
  display: flex;
  align-items: center;
  justify-content: center;
  border-radius: 4px;
  color: var(--yh-color-primary, #409eff);
}
.yh-ai-file-card__media-placeholder--video {
  background: var(--yh-fill-color-light, #f5f7fa);
}
.yh-ai-file-card__media-placeholder--audio {
  background: linear-gradient(135deg, var(--yh-fill-color-light, #f5f7fa) 0%, var(--yh-fill-color, #fafafa) 100%);
}
.yh-ai-file-card__image-loading-overlay {
  position: absolute;
  inset: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  background: rgba(255, 255, 255, 0.5);
  border-radius: 4px;
}
.yh-ai-file-card__image {
  width: 100%;
  height: 100%;
  max-width: 100%;
  max-height: 100%;
  border-radius: 4px;
  object-fit: cover;
}
.yh-ai-file-card__mask {
  position: absolute;
  inset: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  background: rgba(0, 0, 0, 0.5);
  border-radius: 4px;
  color: #fff;
  font-size: 14px;
}
.yh-ai-file-card__file-mask {
  position: absolute;
  inset: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  background: rgba(0, 0, 0, 0.5);
  border-radius: 8px;
  color: #fff;
  font-size: 14px;
}
.yh-ai-file-card__actions {
  position: absolute;
  inset: 0;
  z-index: 80;
  pointer-events: none;
}
.yh-ai-file-card__actions > * {
  pointer-events: auto;
}

.yh-ai-file-card__name-tooltip {
  max-width: 320px;
}
.yh-ai-file-card__name-tooltip .yh-tooltip__content {
  word-break: break-all;
  overflow-wrap: break-word;
  white-space: normal;
  overflow-x: hidden;
}
</style>
