<template>
  <!-- 文本：直接显示纯文本 -->
  <span v-if="isText" class="whitespace-pre-wrap break-all">{{ textContent }}</span>

  <!-- 图片：缩略图 + 点击放大 -->
  <el-image
    v-else-if="isImage && imagePayload"
    class="w-60px h-60px rounded align-middle"
    :src="imagePayload.thumbnailUrl || imagePayload.url"
    :preview-src-list="[imagePayload.url]"
    :preview-teleported="true"
    fit="cover"
  />

  <!-- 文件：图标 + 名称 + 大小，单行内显示 -->
  <span v-else-if="isFile && filePayload" class="inline-flex gap-1.5 items-center">
    <Icon :icon="fileIconInfo.icon" :color="fileIconInfo.color" :size="18" />
    <span class="max-w-200px truncate">{{ filePayload.name }}</span>
    <span v-if="filePayload.size" class="text-12px text-[var(--el-text-color-secondary)]">
      {{ formatFileSize(filePayload.size) }}
    </span>
  </span>

  <!-- 语音：图标 + 时长 -->
  <span v-else-if="isVoice && voicePayload" class="inline-flex gap-1.5 items-center">
    <Icon icon="ant-design:audio-outlined" :size="16" color="#606266" />
    <span>{{ formatSeconds(voicePayload.duration ?? 0) }}</span>
  </span>

  <!-- 视频：封面缩略图 + 时长 + 大小；封面缺失时降级图标占位 -->
  <span v-else-if="isVideo && videoPayload" class="inline-flex gap-1.5 items-center">
    <span
      v-if="videoPayload.coverUrl"
      class="relative inline-block w-60px h-60px rounded overflow-hidden align-middle cursor-pointer"
      :title="videoPayload.url ? '点击新标签播放' : ''"
      @click="openVideo"
    >
      <img :src="videoPayload.coverUrl" class="w-full h-full object-cover" />
      <Icon
        icon="ant-design:play-circle-filled"
        :size="22"
        color="#fff"
        class="absolute inset-0 m-auto pointer-events-none"
        style="filter: drop-shadow(0 0 2px rgba(0, 0, 0, 0.6))"
      />
    </span>
    <span v-else class="inline-flex gap-1.5 items-center">
      <Icon icon="ant-design:video-camera-filled" :size="16" color="#9c27b0" />
      <span>[视频]</span>
    </span>
    <span v-if="videoPayload.duration" class="text-12px text-[var(--el-text-color-secondary)]">
      {{ formatSeconds(videoPayload.duration) }}
    </span>
    <span v-if="videoPayload.size" class="text-12px text-[var(--el-text-color-secondary)]">
      {{ formatFileSize(videoPayload.size) }}
    </span>
  </span>

  <!-- 名片 -->
  <CardLineLabel v-else-if="isCard && cardPayload" :card="cardPayload" :icon-size="16" />

  <!-- 合并转发：title + 前 N 条摘要 -->
  <span v-else-if="isMerge && mergePayload" class="inline-flex flex-col gap-0.5 align-middle">
    <span class="text-13px text-[var(--el-text-color-primary)]">[聊天记录] {{ mergePayload.title }}</span>
    <span
      v-for="(line, idx) in mergePreviewLines"
      :key="idx"
      class="text-12px truncate text-[var(--el-text-color-secondary)]"
    >
      {{ line }}
    </span>
  </span>

  <!-- 表情贴图：缩略图 + 表情名（无名字时仅 [表情]） -->
  <span v-else-if="isFace && facePayload" class="inline-flex gap-1.5 items-center">
    <img
      v-if="facePayload.url"
      :src="facePayload.url"
      :alt="facePayload.name || '表情'"
      class="w-30px h-30px rounded object-contain align-middle"
      draggable="false"
    />
    <span>{{ buildFacePreviewText(facePayload) }}</span>
  </span>

  <!-- 控制类消息：撤回 / 已读 / 回执 -->
  <span
    v-else-if="props.type === ImMessageType.RECALL"
    class="text-12px text-[var(--el-text-color-secondary)]"
  >
    [消息已撤回]
  </span>
  <span
    v-else-if="props.type === ImMessageType.READ"
    class="text-12px text-[var(--el-text-color-secondary)]"
  >
    [已读回执]
  </span>
  <span
    v-else-if="props.type === ImMessageType.RECEIPT"
    class="text-12px text-[var(--el-text-color-secondary)]"
  >
    [回执]
  </span>

  <!-- 群广播事件：拼装中文 tip 文案，operator 用 senderNickname，member / newOwner 退化为 用户(id) -->
  <span
    v-else-if="isGroupNotificationType"
    class="text-12px text-[var(--el-text-color-secondary)]"
  >
    {{ groupNotificationText }}
  </span>

  <!-- 好友会话事件（FRIEND_ADD / FRIEND_DELETE）：固定中文文案 -->
  <span
    v-else-if="isFriendChatTipType"
    class="text-12px text-[var(--el-text-color-secondary)]"
  >
    {{ friendChatTipText }}
  </span>

  <!-- 通话事件（RTC_CALL_START / RTC_CALL_END）：中文文案 + 媒体类型 / 结束原因 / 时长 -->
  <span
    v-else-if="isRtcCallTipType"
    class="inline-flex gap-1.5 items-center text-12px text-[var(--el-text-color-secondary)]"
  >
    <Icon icon="ant-design:phone-outlined" :size="14" class="rotate-[135deg]" />
    <span>{{ rtcCallTipText }}</span>
  </span>

  <!-- 其它系统事件 / 未知类型：content 通常是结构化 JSON，回退原始预览 -->
  <span v-else class="whitespace-pre-wrap break-all">{{ fallbackText }}</span>
</template>

<script lang="ts" setup>
import { computed } from 'vue'
import Icon from '@/components/Icon/src/Icon.vue'
import { formatFileSize } from '@/utils/file'
import { formatSeconds } from '@/utils/formatTime'
import { DICT_TYPE, getDictLabel } from '@/utils/dict'
import {
  ImMessageType,
  ImRtcCallEndReason,
  ImRtcCallMediaType,
  isFriendChatTip,
  isGroupNotification,
  isRtcCallTip
} from '@/views/im/utils/constants'
import { MESSAGE_MERGE_PREVIEW_LINES } from '@/views/im/utils/config'
import CardLineLabel from '@/views/im/home/components/card/CardLineLabel.vue'
import {
  parseMessage,
  parseRtcCallPayload,
  getFileIconInfo,
  resolveFriendNotificationText,
  resolveGroupNotificationText,
  type ImageMessage,
  type FileMessage,
  type AudioMessage,
  type VideoMessage,
  type TextMessage,
  type CardMessage,
  type FaceMessage,
  type MergeMessage
} from '@/views/im/utils/message'
import { buildFacePreviewText, summarizeMessageContent } from '@/views/im/utils/conversation'

defineOptions({ name: 'ImMessageContentPreview' })

const props = defineProps<{
  /** 消息类型，对应 ImMessageType */
  type?: number
  /** 消息 content（JSON 字符串或裸文本） */
  content?: string
  /** 发送人昵称：群广播事件用作 operatorName 兜底渲染 */
  senderNickname?: string
}>()

/** 各类型判定 */
const isText = computed(() => props.type === ImMessageType.TEXT)
const isImage = computed(() => props.type === ImMessageType.IMAGE)
const isFile = computed(() => props.type === ImMessageType.FILE)
const isVoice = computed(() => props.type === ImMessageType.VOICE)
const isVideo = computed(() => props.type === ImMessageType.VIDEO)
const isCard = computed(() => props.type === ImMessageType.CARD)
const isFace = computed(() => props.type === ImMessageType.FACE)
const isMerge = computed(() => props.type === ImMessageType.MERGE)

/** 文本内容：从 TextMessage payload 取 .content */
const textContent = computed(
  () => parseMessage<TextMessage>(props.content || '')?.content ?? ''
)

const imagePayload = computed(() =>
  isImage.value ? parseMessage<ImageMessage>(props.content || '') : null
)
const filePayload = computed(() =>
  isFile.value ? parseMessage<FileMessage>(props.content || '') : null
)
const voicePayload = computed(() =>
  isVoice.value ? parseMessage<AudioMessage>(props.content || '') : null
)
const videoPayload = computed(() =>
  isVideo.value ? parseMessage<VideoMessage>(props.content || '') : null
)
const cardPayload = computed(() =>
  isCard.value ? parseMessage<CardMessage>(props.content || '') : null
)
const facePayload = computed(() =>
  isFace.value ? parseMessage<FaceMessage>(props.content || '') : null
)
const mergePayload = computed(() =>
  isMerge.value ? parseMessage<MergeMessage>(props.content || '') : null
)

/** 合并转发预览行：取前 N 条派生「{昵称}：{摘要}」 */
const mergePreviewLines = computed(() => {
  if (!mergePayload.value) {
    return []
  }
  return mergePayload.value.messages
    .slice(0, MESSAGE_MERGE_PREVIEW_LINES)
    .map((item) => `${item.senderNickname}：${summarizeMessageContent(item)}`)
})

/** 点击视频封面：在新标签打开视频 url（不在管理后台内嵌播放，避免列表里多个 video 同时占资源） */
function openVideo() {
  const url = videoPayload.value?.url
  if (url) {
    // noopener,noreferrer 切断新窗口对原页面的 window.opener 引用，防 Tabnabbing
    window.open(url, '_blank', 'noopener,noreferrer')
  }
}

/** 文件图标：按扩展名分配 icon + 颜色 */
const fileIconInfo = computed(() => getFileIconInfo(filePayload.value?.name))

/** 系统事件 / 未知类型 fallback：取 JSON 首层 content，否则原文 */
const fallbackText = computed(() => {
  const raw = props.content || ''
  if (!raw) {
    return ''
  }
  try {
    const parsed = JSON.parse(raw)
    if (parsed && typeof parsed === 'object' && parsed.content) {
      return String(parsed.content)
    }
  } catch {}
  return raw
})

/** 是否好友会话事件气泡（FRIEND_ADD / FRIEND_DELETE） */
const isFriendChatTipType = computed(() => isFriendChatTip(props.type ?? -1))

/** 好友会话事件文案：固定文案，不依赖 payload */
const friendChatTipText = computed(() => resolveFriendNotificationText({ type: props.type }))

/** 是否群广播事件 */
const isGroupNotificationType = computed(() => isGroupNotification(props.type ?? -1))

/** 群广播事件文案：admin 端 operator 用 senderNickname 直接覆盖，其它 id 退化为 用户(id) */
const groupNotificationText = computed(() =>
  resolveGroupNotificationText(
    { type: props.type, content: props.content },
    (id) => `用户(${id})`,
    props.senderNickname
  )
)

/** 是否通话事件气泡（RTC_CALL_START / RTC_CALL_END） */
const isRtcCallTipType = computed(() => isRtcCallTip(props.type ?? -1))

/** 通话事件文案：START 显示「{发起人} 发起了{媒体}通话」；END 显示「{媒体}通话已结束 [原因] [时长]」 */
const rtcCallTipText = computed(() => {
  const payload = parseRtcCallPayload(props.content)
  if (!payload) {
    return ''
  }
  const mediaLabel = payload.mediaType === ImRtcCallMediaType.VIDEO ? '视频' : '语音'
  if (props.type === ImMessageType.RTC_CALL_START) {
    const inviter = payload.inviterNickname?.trim() || `用户(${payload.inviterUserId ?? ''})`
    return `${inviter} 发起了${mediaLabel}通话`
  }
  // RTC_CALL_END
  const segments = [`${mediaLabel}通话已结束`]
  // HANGUP 字典 label 是「通话结束」，会和前缀重复；跳过
  if (payload.endReason && payload.endReason !== ImRtcCallEndReason.HANGUP) {
    const reason = getDictLabel(DICT_TYPE.IM_RTC_CALL_END_REASON, payload.endReason)
    if (reason) {
      segments.push(reason)
    }
  }
  const duration = payload.durationSeconds ?? 0
  if (duration > 0) {
    segments.push(`时长 ${formatSeconds(duration)}`)
  }
  return segments.join('，')
})
</script>
