<template>
    <div class="simple-message-list message-list-container">
        <div ref="messageListRef" class="message-scroll-list">
            <div v-for="(message, index) in normalizedMessageList" :id="message.ID"
                :key="message.ID || `message-${index}`" class="message-item">
                <MessageTimestamp :curr-time="message.time" :prev-time="normalizedMessageList[index - 1]?.time || 0" />
                <div class="message-element">
                    <RevokedMessage v-if="message.isRevoked" :message="message" :re-edit-message="handleReEditMessage"
                        :session-state="sessionState" />
                    <template v-else-if="message.type === MESSAGE_TYPES.MSG_GRP_TIP">
                        <div class="message-system-tip">
                            {{ formatGroupTipsMessage(message) }}
                        </div>
                    </template>
                    <MessageBubble v-else :message="message" :session-state="sessionState" :session-user-name="''"
                        :is-group-session="false" :session-user-id="''" :peer-source="'0'"
                        :message-list-dom="messageListRef" :current-user-id="currentUserId" :current-menu-sub="'merge'"
                        :staff-show-read-receipt="0">
                        <TextMessage v-if="message.type === MESSAGE_TYPES.MSG_TEXT" :data="message.payload" />

                        <ImageMessage v-else-if="message.type === MESSAGE_TYPES.MSG_IMAGE"
                            :image-content="getImageContent(message)" :meida-message-onload="handleMediaLoaded"
                            :preview-image="() => openImagePreview(message)" />

                        <VideoMessage v-else-if="message.type === MESSAGE_TYPES.MSG_VIDEO"
                            :meida-message-onload="handleMediaLoaded" :video-content="getVideoContent(message)" />

                        <AudioMessage v-else-if="message.type === MESSAGE_TYPES.MSG_AUDIO"
                            :audio-content="getAudioContent(message)" :is-seat-side="isSeatSideMessage(message)" />

                        <FileMessage v-else-if="message.type === MESSAGE_TYPES.MSG_FILE"
                            :file-content="getFileContent(message)" :is-seat-side="isSeatSideMessage(message)"
                            :preview-image="() => openImagePreview(message)"
                            :meida-message-onload="handleMediaLoaded" />

                        <MergeMessage v-else-if="message.type === MESSAGE_TYPES.MSG_MERGER"
                            :merge-content="getMergeContent(message)" :current-user-id="currentUserId" />

                        <CustomMessage v-else-if="message.type === MESSAGE_TYPES.MSG_CUSTOM"
                            :custom-content="message.payload" :message="message" />

                        <div v-else class="unsupported-message-card">
                            {{ t('暂不支持的消息类型：{type}', { type: message.type || 'unknown' }) }}
                        </div>
                    </MessageBubble>
                </div>
            </div>
        </div>

        <MobileImagePreview :visible="mobileImagePreviewVisible" :images="mobileImagePreviewList"
            :active-index="mobileImagePreviewIndex" @close="closeMobileImagePreview"
            @update:active-index="handleMobileImagePreviewIndexChange" />

        <FloatingImageWindow v-for="win in windows" :key="win.id" :state="win" @close="closeWindow"
            @bring-to-front="bringToFront" @update="updateWindow" />
    </div>
</template>

<script setup lang="ts">
import { computed, ref } from 'vue'
import { useI18n } from 'vue-i18n'

import {
    MESSAGE_TYPES,
    type IMessageModel,
    type SessionState,
} from '@tencentcloud/ai-desk-core'

import {
    formatGroupTipsMessage,
    getPreviewableImageItems,
    isSeatSideMessage,
    type PreviewImageItem,
} from '../../../../utils'
import { isMobile } from '../../../../utils/env'
import { useFloatingImageManager } from '../../useFloatingImageManager'
import AudioMessage from '../AudioMessage/index.vue'
import CustomMessage from '../CustomMeaage/index.vue'
import FileMessage from '../FileMessage.vue'
import FloatingImageWindow from '../FloatingImageWindow.vue'
import ImageMessage from '../ImageMessage.vue'
import MessageBubble from '../MessageBubble/index.vue'
import MessageTimestamp from '../MessageTimestamp.vue'
import MobileImagePreview from '../MobileImagePreview.vue'
import RevokedMessage from '../RevokedMessage.vue'
import TextMessage from '../TextMessage/index.vue'
import VideoMessage from '../VideoMessage.vue'
import MergeMessage from './index.vue'

interface MergeMessageBodyItem {
    type?: unknown
    payload?: Record<string, unknown> | null
}

interface MergeMessageItem {
    avatar?: unknown
    ID?: unknown
    cloudCustomData?: unknown
    conversationID?: unknown
    flow?: unknown
    from?: unknown
    isRevoked?: unknown
    messageBody?: MergeMessageBodyItem[] | null
    needReadReceipt?: unknown
    nick?: unknown
    payload?: Record<string, unknown> | null
    readReceiptInfo?: unknown
    status?: unknown
    time?: unknown
    type?: unknown
}

interface MobilePreviewImageItem {
    id: string
    url: string
}

interface Props {
    messageList?: MergeMessageItem[] | null
    currentUserId?: string
}

const props = withDefaults(defineProps<Props>(), {
    messageList: () => [],
    currentUserId: '',
})

const { t } = useI18n()

const sessionState: SessionState = 'finished'
const messageListRef = ref<HTMLDivElement | null>(null)
const mobileImagePreviewVisible = ref(false)
const mobileImagePreviewIndex = ref(0)
const { windows, openImage, closeWindow, bringToFront, updateWindow } = useFloatingImageManager()

const safeToString = (input: unknown): string => {
    if (typeof input === 'string') {
        return input
    }

    if (typeof input === 'number' || typeof input === 'boolean') {
        return String(input)
    }

    return ''
}

const normalizeTime = (input: unknown): string | number => {
    if (typeof input === 'string' && input.trim() !== '') {
        return input
    }

    if (typeof input === 'number' && Number.isFinite(input)) {
        return input
    }

    return Date.now()
}

const getMessageId = (message: MergeMessageItem, index: number) => {
    return safeToString(message.ID) || `merge-message-${index}`
}

const getPrimaryBody = (message: MergeMessageItem) => {
    if (Array.isArray(message.messageBody) && message.messageBody.length > 0) {
        const primaryBody = message.messageBody[0]
        return {
            type: safeToString(primaryBody?.type),
            payload: primaryBody?.payload && typeof primaryBody.payload === 'object'
                ? primaryBody.payload
                : {},
        }
    }

    return {
        type: safeToString(message.type),
        payload: message.payload && typeof message.payload === 'object' ? message.payload : {},
    }
}

const normalizeFlow = (message: MergeMessageItem) => {
    const rawFlow = safeToString(message.flow)
    if (rawFlow === 'in' || rawFlow === 'out') {
        return rawFlow
    }

    const fromUserId = safeToString(message.from)
    if (props.currentUserId && fromUserId === props.currentUserId) {
        return 'out'
    }

    return 'in'
}

const normalizedMessageList = computed<IMessageModel[]>(() => {
    if (!Array.isArray(props.messageList)) {
        return []
    }

    return props.messageList.map((message, index) => {
        const primaryBody = getPrimaryBody(message)

        return {
            ID: getMessageId(message, index),
            type: primaryBody.type,
            payload: primaryBody.payload,
            time: normalizeTime(message.time),
            flow: normalizeFlow(message),
            from: safeToString(message.from),
            nick: safeToString(message.nick),
            isRevoked: Boolean(message.isRevoked),
            cloudCustomData: safeToString(message.cloudCustomData),
            conversationID: safeToString(message.conversationID),
            status: safeToString(message.status),
            needReadReceipt: Boolean(message.needReadReceipt),
            readReceiptInfo: message.readReceiptInfo && typeof message.readReceiptInfo === 'object'
                ? message.readReceiptInfo as IMessageModel['readReceiptInfo']
                : undefined,
            avatar: safeToString(message.avatar),
        } as IMessageModel
    })
})

const sessionImageList = computed<PreviewImageItem[]>(() => {
    return normalizedMessageList.value.flatMap((item) => getPreviewableImageItems(item))
})

const mobileImagePreviewList = computed<MobilePreviewImageItem[]>(() => {
    return sessionImageList.value.map((item) => ({
        id: item.messageId,
        url: item.src,
    }))
})

const getImageContent = (message: IMessageModel) => {
    const imageInfo = message.payload?.imageInfoArray?.[0] ?? {}
    return {
        url: imageInfo.url ?? '',
    }
}

const getVideoContent = (message: IMessageModel) => {
    return {
        url: message.payload?.videoUrl,
        snapshotUrl: message.payload?.snapshotUrl || message.payload?.thumbUrl,
        snapshotWidth: message.payload?.snapshotWidth || message.payload?.thumbWidth,
        snapshotHeight: message.payload?.snapshotHeight || message.payload?.thumbHeight,
    }
}

const getAudioContent = (message: IMessageModel) => {
    return {
        url: message.payload?.url ?? '',
        second: Number(message.payload?.second) || 1,
    }
}

const getFileContent = (message: IMessageModel) => {
    return {
        name: message.payload?.fileName ?? message.payload?.name ?? '',
        url: message.payload?.fileUrl ?? message.payload?.url ?? '',
        size: message.payload?.fileSize ?? message.payload?.size ?? '',
        uploadProgress: message.payload?.uploadProgress,
    }
}

const getMergeContent = (message: IMessageModel) => {
    return {
        messageList: message.payload?.messageList ?? [],
        title: message.payload?.title ?? '',
        abstractList: message.payload?.abstractList ?? [],
        cloudCustomData: message?.cloudCustomData ?? '',
    };
}

const handleReEditMessage = (_message: IMessageModel) => {
}

const closeMobileImagePreview = () => {
    mobileImagePreviewVisible.value = false
}

const handleMobileImagePreviewIndexChange = (index: number) => {
    mobileImagePreviewIndex.value = index
}

const openImagePreview = (message: IMessageModel) => {
    const currentImage = sessionImageList.value.find((item) => item.messageId === message.ID)
    if (!currentImage) {
        return
    }

    if (!isMobile) {
        openImage({
            imageId: currentImage.messageId,
            src: currentImage.src,
            imageList: sessionImageList.value.map((item) => ({
                id: item.messageId,
                src: item.src,
            })),
        })
        return
    }

    const targetIndex = mobileImagePreviewList.value.findIndex((item) => item.id === currentImage.messageId)
    mobileImagePreviewIndex.value = targetIndex >= 0 ? targetIndex : 0
    mobileImagePreviewVisible.value = true
}

const handleMediaLoaded = () => {
}
</script>

<style scoped>
.simple-message-list {
    width: 100%;
    height: 100%;
    flex: 1 1 auto;
    min-height: 0;
    min-width: 0;
    background: #f5f7fa;
    overflow: hidden;
}

.message-list-container {
    width: 100%;
    height: 100%;
    display: flex;
    flex-direction: column;
    overflow: hidden;
    position: relative;
    background: #f5f7fa;
}

.message-scroll-list {
    flex: 1;
    min-height: 0;
    overflow-x: hidden;
    overflow-y: auto;
    -webkit-overflow-scrolling: touch;
    overscroll-behavior: contain;
    touch-action: pan-y;
    padding: 16px 12px 20px;
}

.message-scroll-list::-webkit-scrollbar {
    width: 5px;
}

.message-scroll-list::-webkit-scrollbar-track {
    background: transparent;
}

.message-scroll-list::-webkit-scrollbar-thumb {
    background: #c7cad1;
    border-radius: 999px;
    visibility: hidden;
}

.message-scroll-list:hover::-webkit-scrollbar-thumb {
    visibility: visible;
}

.message-item {
    display: flex;
    flex-direction: column;
}

.message-element {
    display: flex;
    flex-direction: column;
}

.message-system-tip {
    display: flex;
    justify-content: center;
    width: 100%;
    margin-bottom: 10px;
    font-size: 12px;
    color: #999;
    text-align: center;
}

.unsupported-message-card {
    display: flex;
    flex-direction: column;
    gap: 8px;
    font-size: 14px;
    line-height: 1.6;
    color: #4f566b;
    white-space: pre-wrap;
}
</style>
