<template>
	<Connected v-if="showConnected" :room="room" @disconnect="disconnect" />

	<div v-if="showAccept" class="mb-[64px] flex flex-row justify-around px-2">
		<div class="flex flex-col items-center" @click.stop="disconnect">
			<img class="h-[62px] w-[62px]" :src="hungup" alt="hungup" />
			<span class="mt-2 text-sm text-white">{{ $t('rtc.hungup') }}</span>
		</div>
		<div class="flex flex-col items-center" @click.stop="acceptInvitation">
			<img class="h-[62px] w-[62px]" :src="accept" alt="accept" />
			<span class="mt-2 text-sm text-white">{{ $t('rtc.accept') }}</span>
		</div>
	</div>
</template>

<script lang="ts" setup>
	import hungup from '@/assets/images/rtc/hungup.png'
	import accept from '@/assets/images/rtc/accept.png'
	import type { RtcInvite, WSEvent } from 'open-im-sdk-wasm/lib/types/entity'
	import { AuthData, InviteData, RtcInviteResults } from '../data'
	import { IMSDK } from '@/utils/imCommon'
	import useUserStore from '@/store/modules/user'
	import { SessionType, CbEvents } from 'open-im-sdk-wasm'
	import { CustomMessageType, RtcMessageStatus } from '@/constants/enum'
	import useMessageStore, { ExMessageItem } from '@/store/modules/message'
	import useConversationStore from '@/store/modules/conversation'
	import emitter from '@/utils/events'
	import { RemoteParticipant, Room, RoomEvent } from 'livekit-client'
	import Connected from './Connected.vue'
	import { getBusinessInfo } from '@/api/user'

	type IRtcControlEmits = {
		(event : 'connectRtc', data ?: AuthData) : void
		(event : 'closeOverlay') : void
	}
	type IRtcControlProps = {
		room : Room
		isWaiting : boolean
		isConnected : boolean
		duration : string
		invitation : RtcInvite
		inviteData : InviteData
	}
	const emit = defineEmits<IRtcControlEmits>()
	const props = defineProps<IRtcControlProps>()

	const hasJoin = ref(false)
	const isAccept = ref(false)
	const isSingle = computed(() => props.invitation.sessionType === SessionType.Single)
	const isRecv = computed(
		() => userStore.selfInfo.userID !== props.invitation?.inviterUserID,
	)
	const showAccept = computed(() => {
		if (props.inviteData.isJoin) {
			return false
		}
		if (!isRecv.value) {
			return false
		}
		return !props.isConnected
	})
	const showConnected = computed(() => props.isConnected || !isRecv.value)

	const userStore = useUserStore()
	const messageStore = useMessageStore()
	const conversationStore = useConversationStore()

	const insertRtcMessage = async (status : RtcMessageStatus) => {
		if (props.invitation.sessionType !== SessionType.Single) return
		const message = (
			await IMSDK.createCustomMessage({
				data: JSON.stringify({
					customType: CustomMessageType.Call,
					data: {
						duration: props.duration,
						mediaType: props.invitation.mediaType,
						status,
					},
				}),
				extension: '',
				description: '',
			})
		).data
		if (!message) return

		const fullMessage = (
			await IMSDK.insertSingleMessageToLocalStorage<ExMessageItem>({
				recvID: props.invitation.inviteeUserIDList[0],
				sendID: props.invitation.inviterUserID,
				message,
			})
		).data

		const userInfo = {
			id: '',
			name: '',
			faceUrl: '',
		}

		const getUserInfo = async () => {
			if (props.invitation.inviterUserID === userStore.selfInfo.userID) {
				const res = await getBusinessInfo(props.invitation.inviteeUserIDList[0])
				const businessData = res.data.users[0] ?? {}
				userInfo.id = props.invitation.inviteeUserIDList[0]
				userInfo.name = businessData.nickname
				userInfo.faceUrl = businessData.faceURL
			} else {
				const res = await getBusinessInfo(props.invitation.inviterUserID)
				const businessData = res.data.users[0] ?? {}
				userInfo.id = props.invitation.inviterUserID
				userInfo.name = businessData.nickname
				userInfo.faceUrl = businessData.faceURL
			}
		}
		await getUserInfo()

		insertRtcMessageToLocalStorage({ ...fullMessage, status, userInfo })

		const conversation = conversationStore.currentConversation
		if (
			props.invitation.inviterUserID === conversation?.userID ||
			props.invitation.inviteeUserIDList[0] === conversation?.userID
		) {
			messageStore.pushNewMessage(fullMessage)
		}
	}

	const insertRtcMessageToLocalStorage = (fullMessage : any) => {
		let historyList = []
		try {
			const storedHistory = localStorage.getItem(
				`${userStore.selfInfo.userID}_rtc_historyList`,
			)
			if (storedHistory) {
				historyList = JSON.parse(storedHistory)
			}
		} catch (e) { }
		historyList.push({
			...fullMessage,
			time: new Date().getTime(),
		})
		localStorage.setItem(
			`${userStore.selfInfo.userID}_rtc_historyList`,
			JSON.stringify(historyList),
		)
	}

	const acceptInvitation = () => {
		if (isAccept.value) return
		isAccept.value = true
		IMSDK.signalingAccept<RtcInviteResults>({
			opUserID: userStore.selfInfo.userID,
			invitation: props.invitation,
		})
			.then(({ data }) => {
				emit('connectRtc', {
					liveURL: data.liveURL,
					token: data.token,
				})
			})
			.catch((error) => console.log(error))
	}

	const disconnect = () => {
		const data = {
			opUserID: userStore.selfInfo.userID,
			invitation: props.invitation,
		}
		if (props.isWaiting) {
			const funcName = isRecv.value ? 'signalingReject' : 'signalingCancel'
			IMSDK[funcName](data)
			insertRtcMessage(
				isRecv.value ? RtcMessageStatus.Refused : RtcMessageStatus.Canceled,
			)
			emitter.emit('CLOSE_RTC_MODAL')
			return
		}
		IMSDK.signalingHungUp(data)
		insertRtcMessage(RtcMessageStatus.Successed)
		props.room.disconnect()
		emitter.emit('CLOSE_RTC_MODAL')
	}

	const acceptHandler = ({
		data: {
			invitation: { roomID },
		},
	} : WSEvent<{ invitation : RtcInvite }>) => {
		if (props.invitation.roomID !== roomID) return

		if (isSingle.value) {
			emit('connectRtc', undefined)
		} else {
			hasJoin.value = true
		}
	}

	const rejectHandler = ({
		data: {
			invitation: { roomID },
		},
	} : WSEvent<{ invitation : RtcInvite }>) => {
		if (props.invitation.roomID !== roomID || !isSingle.value) return
		insertRtcMessage(RtcMessageStatus.Refused)
		emitter.emit('CLOSE_RTC_MODAL')
	}

	const hangupHandler = ({
		data: {
			invitation: { roomID },
		},
	} : WSEvent<{ invitation : RtcInvite }>) => {
		if ((!isSingle.value && !props.isWaiting) || props.invitation.roomID !== roomID)
			return
		insertRtcMessage(RtcMessageStatus.Successed)
		props.room.disconnect()
		emitter.emit('CLOSE_RTC_MODAL')
	}

	const cancelHandler = ({
		data: {
			invitation: { roomID },
		},
	} : WSEvent<{ invitation : RtcInvite }>) => {
		if (props.invitation.roomID !== roomID) return
		if (!isSingle.value && !props.isWaiting) return
		insertRtcMessage(RtcMessageStatus.Canceled)
		emitter.emit('CLOSE_RTC_MODAL')
	}

	const timeoutHandler = ({
		data: {
			invitation: { roomID },
		},
	} : WSEvent<{ invitation : RtcInvite }>) => {
		if (props.invitation.roomID !== roomID) return

		if (isSingle.value || !hasJoin.value) {
			insertRtcMessage(RtcMessageStatus.Timeout)
			IMSDK.signalingCancel({
				opUserID: userStore.selfInfo.userID,
				invitation: props.invitation,
			})
			if (!isSingle.value) props.room.disconnect()
			emitter.emit('CLOSE_RTC_MODAL')
		}
	}

	const handleByOtherDevice = ({
		data: {
			invitation: { roomID },
		},
	} : WSEvent<{ invitation : RtcInvite }>) => {
		if (props.invitation.roomID !== roomID) return
		insertRtcMessage(RtcMessageStatus.HandleByOtherDevice)
		emitter.emit('CLOSE_RTC_MODAL')
	}

	const participantDisconnectedHandler = (remoteParticipant : RemoteParticipant) => {
		if (!isSingle.value) return

		const identity = remoteParticipant.identity
		if (
			identity === props.invitation.inviterUserID ||
			identity === props.invitation.inviteeUserIDList[0]
		) {
			insertRtcMessage(RtcMessageStatus.Successed)
			props.room.disconnect()
			emitter.emit('CLOSE_RTC_MODAL')
		}
	}

	onMounted(() => {
		IMSDK.on(CbEvents.OnInviteeAccepted, acceptHandler)
		IMSDK.on(CbEvents.OnInviteeRejected, rejectHandler)
		IMSDK.on(CbEvents.OnHangUp, hangupHandler)
		IMSDK.on(CbEvents.OnInvitationCancelled, cancelHandler)
		IMSDK.on(CbEvents.OnInvitationTimeout, timeoutHandler)
		IMSDK.on(CbEvents.OnInviteeAcceptedByOtherDevice, handleByOtherDevice)
		IMSDK.on(CbEvents.OnInviteeRejectedByOtherDevice, handleByOtherDevice)
		props.room.on(RoomEvent.ParticipantDisconnected, participantDisconnectedHandler)
	})

	onUnmounted(() => {
		IMSDK.off(CbEvents.OnInviteeAccepted, acceptHandler)
		IMSDK.off(CbEvents.OnInviteeRejected, rejectHandler)
		IMSDK.off(CbEvents.OnHangUp, hangupHandler)
		IMSDK.off(CbEvents.OnInvitationCancelled, cancelHandler)
		IMSDK.off(CbEvents.OnInvitationTimeout, timeoutHandler)
		IMSDK.off(CbEvents.OnInviteeAcceptedByOtherDevice, handleByOtherDevice)
		IMSDK.off(CbEvents.OnInviteeRejectedByOtherDevice, handleByOtherDevice)
		props.room.off(RoomEvent.ParticipantDisconnected, participantDisconnectedHandler)
	})
</script>