<template>
	<view class="live-chat">
		<view v-if="enterNoticeVisible" class="live-chat-enter">
			<text class="live-chat-enter-txt">{{ enterNoticeNickname }} 他来了他来了~</text>
		</view>
		<scroll-view
			scroll-y="true"
			class="live-chat-scroll"
			:scroll-into-view="scrollAnchorId"
			:scroll-with-animation="true"
			:show-scrollbar="false"
		>
			<view
				v-for="(row, index) in msgList"
				:key="row.id"
				:id="'liveMsg' + index"
				class="live-chat-row"
			>
				<view class="live-chat-bubble">
					<image
						v-if="row.avatar"
						class="live-chat-av"
						:src="rowAvatar(row.avatar)"
						mode="aspectFill"
					/>
					<view v-else class="live-chat-av live-chat-av-fallback">
						<text class="live-chat-av-letter">{{ avatarLetter(row.user) }}</text>
					</view>
					<text class="live-chat-user" :style="{ color: rowColor(row.userId) }">{{ row.user }} : </text>
					<text class="live-chat-text">{{ row.text }}</text>
				</view>
			</view>
		</scroll-view>
	</view>
</template>

<script>
import appSettings from '@/core/config/app-settings'
import {
	appendChatLine,
	chatLineFingerprint,
	extractChatLine,
	extractEnterNotice,
	isChatDisplayType,
	nicknameColor
} from '@/features/live/chat-lines'

const WELCOME_TEXT = 'Beware of being deceived！'

export default {
	name: 'LiveChatPanel',
	data() {
		return {
			msgList: [],
			scrollAnchorId: 'liveMsg0',
			enterNoticeVisible: false,
			enterNoticeNickname: '',
			enterNoticeTimer: null,
			welcomeTimer: null,
			recentFingerprints: []
		}
	},
	beforeDestroy() {
		this.clearWelcomeTimer()
		if (this.enterNoticeTimer) clearTimeout(this.enterNoticeTimer)
	},
	methods: {
		clearWelcomeTimer() {
			if (this.welcomeTimer) {
				clearTimeout(this.welcomeTimer)
				this.welcomeTimer = null
			}
		},
		scheduleWelcomeTip() {
			this.clearWelcomeTimer()
			this.welcomeTimer = setTimeout(() => {
				this.welcomeTimer = null
				this.pushLocalLine({
					userId: '0',
					user: 'Tips',
					avatar: '',
					text: WELCOME_TEXT
				}, true)
			}, 500)
		},
		reset() {
			this.clearWelcomeTimer()
			this.msgList = []
			this.recentFingerprints = []
			this.enterNoticeVisible = false
			this.enterNoticeNickname = ''
			if (this.enterNoticeTimer) clearTimeout(this.enterNoticeTimer)
			this.scheduleWelcomeTip()
		},
		onMessage(msg) {
			const notice = extractEnterNotice(msg)
			if (notice) {
				this.showEnterNotice(notice.nickname)
			}

			const inner = msg?.message
			const innerType = inner && typeof inner === 'object' ? inner.type : ''
			if (innerType && !isChatDisplayType(innerType)) return

			const line = extractChatLine(msg)
			if (!line) return
			if (this.isDuplicate(line)) return
			this.pushLocalLine(line)
		},
		pushLocalLine(line, skipDedupe = false) {
			if (!skipDedupe && line.user === 'Tips' && line.text === WELCOME_TEXT) {
				const exists = this.msgList.some((row) => row.user === 'Tips' && row.text === WELCOME_TEXT)
				if (exists) return
			}
			this.msgList = appendChatLine(this.msgList, line)
			this.$nextTick(() => {
				this.scrollAnchorId = `liveMsg${this.msgList.length - 1}`
			})
		},
		pushOutgoing(line) {
			if (!line || !line.text) return
			if (this.isDuplicate(line)) return
			this.pushLocalLine(line)
		},
		isDuplicate(line) {
			const fp = chatLineFingerprint(line)
			const now = Date.now()
			const recent = this.recentFingerprints.filter((item) => now - item.t < 2000)
			if (recent.some((item) => item.fp === fp)) return true
			this.recentFingerprints = recent.concat([{ fp, t: now }]).slice(-50)
			return false
		},
		showEnterNotice(nickname) {
			if (this.enterNoticeTimer) clearTimeout(this.enterNoticeTimer)
			this.enterNoticeNickname = nickname || '观众'
			this.enterNoticeVisible = true
			this.enterNoticeTimer = setTimeout(() => {
				this.enterNoticeVisible = false
			}, 1000)
		},
		rowAvatar(path) {
			if (!path) return ''
			if (/^https?:\/\//.test(path)) return path
			return `${appSettings.cdnurl}${path}`
		},
		rowColor(userId) {
			return nicknameColor(userId)
		},
		avatarLetter(name) {
			const text = String(name || '?').trim()
			return text ? text.slice(0, 1).toUpperCase() : '?'
		}
	}
}
</script>

<style scoped>
.live-chat {
	position: relative;
	width: 560rpx;
}
.live-chat-enter {
	position: absolute;
	left: 0;
	top: -72rpx;
	background-color: rgba(255, 86, 136, 0.72);
	border-radius: 999rpx;
	padding-top: 8rpx;
	padding-bottom: 8rpx;
	padding-left: 20rpx;
	padding-right: 20rpx;
}
.live-chat-enter-txt {
	color: #ffffff;
	font-size: 26rpx;
}
.live-chat-scroll {
	height: 360rpx;
}
.live-chat-row {
	margin-bottom: 12rpx;
	flex-direction: row;
}
.live-chat-bubble {
	flex-direction: row;
	align-items: center;
	background-color: rgba(0, 0, 0, 0.42);
	border-radius: 999rpx;
	padding-top: 8rpx;
	padding-bottom: 8rpx;
	padding-left: 8rpx;
	padding-right: 20rpx;
	max-width: 560rpx;
}
.live-chat-av {
	width: 48rpx;
	height: 48rpx;
	border-radius: 24rpx;
	margin-right: 10rpx;
}
.live-chat-av-fallback {
	background-color: rgba(255, 255, 255, 0.18);
	justify-content: center;
	align-items: center;
}
.live-chat-av-letter {
	color: #ffffff;
	font-size: 22rpx;
}
.live-chat-user {
	font-size: 24rpx;
	margin-right: 4rpx;
}
.live-chat-text {
	flex: 1;
	color: #ffffff;
	font-size: 24rpx;
}
</style>
