<template>
	<div>
		<div id="chat_footer" class="flex items-center bg-[#F7F7F7] px-3 py-3">
			<img @click="toggleRecording" class="mr-3 h-[26px] min-w-[26px]" :src="recording ? keyboard : audio"
				alt="" />
			<div class="flex-grow">
				<div v-show="recording" ref="recordingBtnRef" @touchmove="touchMoveSpeech" @touchend="endRecord"
					class="flex h-8 items-center justify-center rounded bg-white">
					<span>{{ $t('buttons.holdSpeak') }}</span>
				</div>
				<CustomEdit v-show="!recording" class="bg-[#fff]" ref="inputRef" @change="inputChange"
					@focus="onFocusUpdate(true)" @blur="onFocusUpdate(false)" v-model:input="messageContent"
					:placeholder="$t('placeholder.pleaseInput')" @trigger-at="tryToAtPage" />
				<div v-if="quoteMessage"
					class="relative mt-1 break-all rounded bg-white py-1 pl-1 pr-5 text-xs text-[#666] line-clamp-2">
					{{ quoteMessage }}
					<img class="absolute right-1 top-1" width="16" :src="quote_close" alt=""
						@click="clearQuoteMessage" />
				</div>
			</div>
			<img @click="clickEmojiBtn" class="ml-3 h-[26px] min-w-[26px]" :src="emoji" alt="" />
			<img v-show="!messageContent" @click="clickAddBtn" class="ml-3 h-[26px] min-w-[26px]" :src="add" alt="" />
			<div class="send ml-2" v-show="messageContent" @click="switchTextMessage">
				发送
			</div>
		</div>
		<ChatFooterAction v-show="showActionBar" @closeActionBar="closeActionBar" @getFile="getFile" />
		<ChatFooterEmoji v-show="showEmojiBar" @closeEmojiBar="closeEmojiBar" @emojiClick="emojiClick" />
		<ChatFooterRecording ref="recordingOverlayRef" @recordFinish="recordFinish" />
		<ChatFooterAtPop v-if="showAtPop" @cancel="showAtPop = false" @finish="clickAtItemHandler" />
	</div>
</template>

<script setup lang="ts">
	import add from '@/assets/images/chatFooter/add.png'
	import audio from '@/assets/images/chatFooter/audio.png'
	import emoji from '@/assets/images/chatFooter/emoji.png'
	import keyboard from '@/assets/images/chatFooter/keyboard.png'
	import quote_close from '@/assets/images/chatFooter/quote_close.png'
	import send from '@/assets/images/chatFooter/send.png'

	import CustomEdit from '@/components/CustomEdit/index.vue'
	import ChatFooterAction from './ChatFooterAction.vue'
	import ChatFooterEmoji from './ChatFooterEmoji.vue'
	import ChatFooterRecording from './ChatFooterRecording.vue'
	import { onLongPress, useThrottleFn } from '@vueuse/core'
	import type { GroupMemberItem } from 'open-im-sdk-wasm/lib/types/entity'
	import { MessageType, SessionType } from 'open-im-sdk-wasm'
	import { showToast, UploaderFileListItem } from 'vant'
	import useSendMessage from '@/hooks/useSendMessage'
	import useConversationStore from '@/store/modules/conversation'
	import { formatMessageByType, IMSDK } from '@/utils/imCommon'
	import { feedbackToast } from '@/utils/common'
	import emitter from '@/utils/events'
	import { checkIsSafari } from '@/utils/common'
	import useCreateNomalMessage from './useCreateNomalMessage'
	import useCreateFileMessage from './useCreateFileMessage'
	import ChatFooterAtPop from './ChatFooterAtPop.vue'

	const emit = defineEmits([])
	defineProps()

	const { t } = useI18n()
	const conversationStore = useConversationStore()

	// message
	const messageContent = ref('')
	const inputRef = ref()

	const { createFileMessage } = useCreateFileMessage()

	const { getAtList, switchNomalMessage } = useCreateNomalMessage({
		messageContent,
	})
	const { sendMessage } = useSendMessage()

	const quoteMessage = computed(() =>
		conversationStore.storeQuoteMessage
			? `${t('messageMenu.replay')}：${formatMessageByType(conversationStore.storeQuoteMessage)}`
			: null,
	)

	const clearQuoteMessage = () => {
		conversationStore.updateQuoteMessage()
	}

	const showAtPop = ref(false)

	const tryToAtPage = () => {
		if (conversationStore.storeCurrentConversation.groupID) {
			showAtPop.value = true
		}
	}

	const clickAtItemHandler = ({
		data,
		needDelete,
	} : {
		data : GroupMemberItem[]
		needDelete : boolean
	}) => {
		if (needDelete) {
			inputRef.value.deletePreviousChar()
		}
		const nodes = [] as Node[]
		data.map((member) => {
			const oldList = getAtList()
			if (oldList.find((item) => item.userID === member.userID)) {
				return
			}
			const b = document.createElement('b')
			b.textContent = `@${member.nickname} `
			b.setAttribute('class', 'at_el')
			b.setAttribute('data_id', member.userID)
			b.setAttribute('data_name', member.nickname)
			b.setAttribute('contenteditable', 'false')
			nodes.push(b)
			nodes.push(document.createTextNode('\u200B'))
		})
		inputRef.value.insertAtCursor(nodes)
		showAtPop.value = false
	}

	const inputChange = useThrottleFn(() => {
		if (
			conversationStore.storeCurrentConversation.conversationType !== SessionType.Single
		) {
			return
		}
		IMSDK.typingStatusUpdate({
			recvID: conversationStore.storeCurrentConversation.userID,
			msgTip: 'yes',
		})
	}, 2000)

	const onFocusUpdate = (isFocus : boolean) => {
		if (!checkIsSafari()) {
			return
		}
		setTimeout(() => emitter.emit('KEYBOARD_UPDATE'), 100)
		if (isFocus) {
			setTimeout(() => window.scroll(0, 0), 101)
		}
	}

	const switchTextMessage = async () => {
		const message = await switchNomalMessage();
		console.log(message, 13545646)
		// 判断 message 是否为空或只包含空格/换行
		if (message) {
			if (message.textElem) {
				if (!/^[\s\n]*$/.test(message.textElem.content)) {
					sendMessage({ message });
				} else {
					showToast('内容不能为空');
				}
			} else {
				sendMessage({ message });
			}
		}

		resetState();
	};

	const emojiClick = (str : string) => {
		const parser = new DOMParser()
		const doc = parser.parseFromString(str, 'text/html')
		const nodes = Array.from(doc.body.childNodes)
		inputRef.value.insertAtCursor(nodes)
	}

	const resetState = () => {
		messageContent.value = ''
		conversationStore.updateQuoteMessage()
		inputRef.value.clear()
	}

	// recording
	const recording = ref(false)
	const recordingBtnRef = ref()
	const recordingOverlayRef = ref()

	const onMenuLongPressCall = () => {
		recordingOverlayRef.value.isShowOverlay()
	}

	onLongPress(recordingBtnRef, onMenuLongPressCall, { modifiers: { prevent: true } })

	const toggleRecording = async () => {
		if (!recording.value) {
			try {
				await recordingOverlayRef.value.requestPermission()
			} catch (error) {
				console.log(error)
				showToast(t('messageTip.environmentNotSupported'))
				return
			}
		}
		recording.value = !recording.value
	}

	const touchMoveSpeech = useThrottleFn((event : TouchEvent) => {
		recordingOverlayRef.value.touchMoveSpeech(event)
	}, 250)

	const endRecord = () => {
		recordingOverlayRef.value.isShowOverlay(false)
	}

	const recordFinish = async (blob : File, duration : number) => {
		const { error, message, buffer } = await createFileMessage(
			blob,
			MessageType.VoiceMessage,
			duration,
		)
		if (error || !message) {
			feedbackToast({ error, message: error })
			return
		}
		sendMessage({ message })
	}

	// action bar
	const showActionBar = ref(false)
	const showEmojiBar = ref(false)

	const closeActionBar = () => {
		showActionBar.value = false
	}
	const closeEmojiBar = () => {
		showEmojiBar.value = false
	}
	const clickAddBtn = () => {
		if (showEmojiBar.value) {
			showEmojiBar.value = false
		}
		showActionBar.value = !showActionBar.value
	}
	const clickEmojiBtn = () => {
		if (showActionBar.value) {
			showActionBar.value = false
		}
		showEmojiBar.value = !showEmojiBar.value
	}
	const getFile = async (uploadData : UploaderFileListItem) => {
		let messageType = MessageType.FileMessage
		if (uploadData.file?.type.includes('image')) {
			messageType = MessageType.PictureMessage
		}
		if (uploadData.file?.type.includes('video')) {
			messageType = MessageType.VideoMessage
		}
		const { error, message, buffer, snapBuffer } = await createFileMessage(
			uploadData.file!,
			messageType,
		)
		if (error || !message) {
			feedbackToast({ error, message: error })
			return
		}
		sendMessage({
			message,
		})
	}

	watch(
		() => conversationStore.storeQuoteMessage,
		(val) => {
			if (val) {
				inputRef.value.inputRef.focus()
			}
		},
	)
	const getCleanText = () => {
		let cleanText = messageContent.value
		const atEls = getAtList()
		if (atEls.length > 0) {
			atEls.map((el) => (cleanText = cleanText.replace(el.tag, `@${el.userID}`)))
			const pattern = /@\S+\s/g
			const arr = cleanText.match(pattern)
			arr?.map((item) => {
				const member = atEls.find((el) => el.userID === item.slice(1, -1))
				if (member) {
					const reg = new RegExp(item, 'g')
					cleanText = cleanText.replace(
						reg,
						'<b class="at el" contenteditable="false" data_id="${member.userID}" data_name="${member.nickname}">@${member.nickname} </b>',
					)
				}
			})
		}
		return cleanText
	}
	watch(
		() => conversationStore.currentConversation.conversationID,
		(val, prevCount) => {
			// checkGroupMembership()
			if (messageContent.value && prevCount) {
				const cleanText = getCleanText()
				const trimmedText = cleanText.trim();
				const isSetDraft = trimmedText != '' && trimmedText !== '<br>';
				IMSDK.setConversationDraft({
					conversationID: prevCount,
					draftText: isSetDraft ? trimmedText : ''
				})
			}
		},
		{
			immediate: true,
		},
	)

	onMounted(() => {
		inputRef.value.inputRef.focus()
		emitter.on('AT_SOMEONE', clickAtItemHandler)
	})

	onActivated(() => {
		inputRef.value.clear()
		inputRef.value.inputRef.focus()
		if (!conversationStore.currentConversation.conversationID) return
		const oldDraftText = conversationStore.currentConversation?.draftText
		setTimeout(() => {
			inputRef.value.inputRef.focus()
			const parser = new DOMParser()
			const doc = parser.parseFromString(oldDraftText, 'text/html')
			const nodes = Array.from(doc.body.childNodes)
			inputRef.value.insertAtCursor(nodes)
			IMSDK.setConversationDraft({
				conversationID: conversationStore.currentConversation.conversationID,
				draftText: "",
			})
		}, 50)
	})
	onDeactivated(() => {
		if (!conversationStore.currentConversation.conversationID) return
		const cleanText = getCleanText()
		const trimmedText = cleanText.trim()
		const isSetDraft = trimmedText !== '' && trimmedText !== '<br>'
		IMSDK.setConversationDraft({
			conversationID: conversationStore.currentConversation.conversationID,
			draftText: isSetDraft ? trimmedText : '',
		})
	})

	onUnmounted(() => {
		emitter.off('AT_SOMEONE', clickAtItemHandler)
	})
</script>

<style lang="scss" scoped>
	:deep(.van-button__content) {
		width: max-content;
	}

	.send {
		width: 3.64rem;
		height: 1.95rem;
		display: flex;
		align-items: center;
		justify-content: center;
		font-size: 0.8rem;
		color: #fff;
		background-color: #07C160;
		border-radius: 0.2rem;
	}
</style>