<template>
	<view class="calling" v-show="callingDialog">
		<!-- 等待对方接受 -->
		<view class="calling-waiting" v-if="dialling">
			<view class="calling-waiting-header">
				<u-avatar :src="defaultAvatar" size="240" mode="square"></u-avatar>
			</view>
			<view class="calling-waiting-status">
				<view>正在呼叫{{ toAccount }}</view>
			</view>
			<view class="calling-waiting-button">
				<view class="calling-waiting-button-passed" @click="handleDebounce(leave, 500)">
					<view class="iconfont icon-guaduan"></view>
				</view>
				<view class="calling-waiting-button-mute" @click="micHandler">
					<view class="iconfont icon-mic-on-full" :class="isMicOn ? 'on' : 'off'"></view>
				</view>
			</view>
		</view>
		<!-- 接收方 -->
		<view class="calling-waiting" v-else-if="isDialled">
			<view class="calling-waiting-header">
				<u-avatar :src="defaultAvatar" size="240" mode="square"></u-avatar>
			</view>
			<view class="calling-waiting-status">
				<view>{{ sponsor }}来电</view>
			</view>
			<view class="calling-waiting-button">
				<view class="calling-waiting-button-mute" @click="handleDebounce(accept, 500)">
					<view class="iconfont icon-call"></view>
				</view>
				<view class="calling-waiting-button-passed" @click="handleDebounce(leave, 500)">
					<view class="iconfont icon-guaduan"></view>
				</view>
			</view>
		</view>
		<!-- 正在聊天 -->
		<view class="calling-waiting" v-else-if="calling">
			<view class="calling-waiting-userList">
				<view class="calling-waiting-userList-item" v-for="(item, index) in invitedUserInfo" :key="index">
					<u-avatar :src="item.avatar || defaultAvatar" size="120"></u-avatar>
					<view style="text-align: center;margin-top: 30rpx;">
						<text class="nick-text">{{ item.nick || item.userID }}</text>
						<text v-if="item.isInvitedMicOn === true || item.isInvitedMicOn == undefined"
							class="iconfont icon-yuyin"
							style="color: #006FFF;font-size: 50rpx;margin-left: 10rpx;"></text>
						<text v-else class="iconfont icon-maikefeng-jingyin"
							style="color: #fff;font-size: 50rpx;margin-left: 10rpx;"></text>
					</view>
				</view>
			</view>
			<view class="calling-waiting-duration">
				{{ formatDurationStr }}
			</view>
			<view class="calling-waiting-button">
				<view class="calling-waiting-button-passed" @click="handleDebounce(leave, 500)">
					<view class="iconfont icon-guaduan"></view>
				</view>
				<view class="calling-waiting-button-mute" @click="micHandler">
					<view class="iconfont icon-mic-on-full" :class="isMicOn ? 'on' : 'off'"></view>
				</view>
			</view>
		</view>
	</view>
</template>

<script>
	export default {
		data() {
			return {
				timeout: null,
				callType: 1, //1:audio，2:video
				Trtc: undefined,
				isCamOn: true,
				isMicOn: true,
				isInvitedMicOn: true,
				maskShow: false,
				isLocalMain: true, // 本地视频是否是主屏幕显示
				start: 0,
				end: 0,
				duration: 0,
				hangUpTimer: 0, // 通话计时id
				ready: false,
				dialling: true, // 是否拨打电话中
				calling: false, // 是否通话中
				isDialled: false, // 是否被呼叫
				inviteID: '',
				inviteData: {},
				sponsor: '', // 发起者
				toAccount: '222', // 接收者
				invitedUserID: [], //被邀请者
				invitedNick: '',
				invitedUserInfo: [],
				defaultAvatar: 'https://imgcache.qq.com/open/qcloud/video/act/webim-avatar/avatar-3.png',
				viewLocalDomID: '',
				callingUserList: [], // 参加通话的人 ,不包括自己
				callingType: 'C2C', //区分多人和C2C通话的UI样式
				isStartLocalView: false, //本地是否开启
				callingTips: {
					callEnd: 1, //通话结束
					callTimeout: 5
				},
				callingDialog: false,
				callingInfo: {
					type: 'C2C'
				}
			}
		},
		// onShow() {
		// 	this.initListener();
		// },
		onHide() {
			this.removeListener();
		},
		watch: {
			callingUserList: {
				handler(newValue) {
					console.log(newValue)
				},
				deep: true,
				immediate: true
		 }
		},
		computed: {
			formatDurationStr() {
				return this.$format.formatDuration(this.duration)
			}
		},
		methods: {
			handleDebounce(func, wait) {
				let context = this
				let args = arguments
				if (this.timeout) clearTimeout(this.timeout)
				this.timeout = setTimeout(() => {
					func.apply(context, args)
				}, wait)
			},
			accept() {
				this.trtcCalling.accept({
					inviteID: this.inviteID,
					roomID: this.inviteData.roomID,
					callType: this.inviteData.callType
				}).then((res) => {
					this.changeState('calling', true);
					this.dialling = false;
					this.calling = true;
					this.isDialled = false;
					console.log('接收信息res', res)
					// this.currentUserProfile.nick = res.data.message.nick
				})
			},
			leave() { // 离开房间，发起方挂断
				this.isMicOn = true
				this.isCamOn = true
				this.maskShow = false
				this.isStartLocalView = false
				this.dialling = false;
				this.calling = false;
				this.isDialled = false;
				this.callingDialog = false
				if (!this.calling) { // 还没有通话，单方面挂断
					this.trtcCalling.hangup().then((res) => {
						// this.currentUserProfile.nick = res.data.message.nick
						this.changeState('dialling', false)
						clearTimeout(this.timer)
					})
					return
				}
				this.hangUp() // 通话一段时间之后，某一方面结束通话
			},
			hangUp() { // 通话一段时间之后，某一方挂断电话
				this.changeState('calling', false)
				this.trtcCalling.hangup();
				this.callingDialog = false
				uni.showToast({
					title: '已挂断',
					icon: 'none'
				})
			},
			openDialog() {
				this.callingDialog = true;
				this.dialling = true;
				this.calling = false;
				this.isDialled = false;
			},
			initListener() {
				// sdk内部发生了错误
				this.trtcCalling.on(this.TRTCCalling.EVENT.ERROR, this.handleError)
				// 被邀请进行通话
				this.trtcCalling.on(this.TRTCCalling.EVENT.INVITED, this.handleNewInvitationReceived)
				// 有用户同意进入通话，那么会收到此回调
				this.trtcCalling.on(this.TRTCCalling.EVENT.USER_ENTER, this.handleUserEnter)
				// 如果有用户同意离开通话，那么会收到此回调
				this.trtcCalling.on(this.TRTCCalling.EVENT.USER_LEAVE, this.handleUserLeave)
				// 用户拒绝通话
				this.trtcCalling.on(this.TRTCCalling.EVENT.REJECT, this.handleInviteeReject)
				//邀请方忙线
				this.trtcCalling.on(this.TRTCCalling.EVENT.LINE_BUSY, this.handleInviteeLineBusy)
				// 作为被邀请方会收到，收到该回调说明本次通话被取消了
				this.trtcCalling.on(this.TRTCCalling.EVENT.CALLING_CANCEL, this.handleInviterCancel)
				// 重复登陆，收到该回调说明被踢出房间
				this.trtcCalling.on(this.TRTCCalling.EVENT.KICKED_OUT, this.handleKickedOut)
				// 作为邀请方会收到，收到该回调说明本次通话超时未应答
				this.trtcCalling.on(this.TRTCCalling.EVENT.CALLING_TIMEOUT, this.handleCallTimeout)
				// 邀请用户无应答
				this.trtcCalling.on(this.TRTCCalling.EVENT.NO_RESP, this.handleNoResponse)
				// 收到该回调说明本次通话结束了
				this.trtcCalling.on(this.TRTCCalling.EVENT.CALLING_END, this.handleCallEnd)
				// 远端用户开启/关闭了摄像头, 会收到该回调
				this.trtcCalling.on(this.TRTCCalling.EVENT.USER_VIDEO_AVAILABLE, this.handleUserVideoChange)
				// 远端用户开启/关闭了麦克风, 会收到该回调
				this.trtcCalling.on(this.TRTCCalling.EVENT.USER_AUDIO_AVAILABLE, this.handleUserAudioChange)
			},
			removeListener() {
				this.trtcCalling.off(this.TRTCCalling.EVENT.ERROR, this.handleError)
				this.trtcCalling.off(this.TRTCCalling.EVENT.INVITED, this.handleNewInvitationReceived)
				this.trtcCalling.off(this.TRTCCalling.EVENT.USER_ENTER, this.handleUserEnter)
				this.trtcCalling.off(this.TRTCCalling.EVENT.USER_LEAVE, this.handleUserLeave)
				this.trtcCalling.off(this.TRTCCalling.EVENT.REJECT, this.handleInviteeReject)
				this.trtcCalling.off(this.TRTCCalling.EVENT.LINE_BUSY, this.handleInviteeLineBusy)
				this.trtcCalling.off(this.TRTCCalling.EVENT.CALLING_CANCEL, this.handleInviterCancel)
				this.trtcCalling.off(this.TRTCCalling.EVENT.KICKED_OUT, this.handleKickedOut)
				this.trtcCalling.off(this.TRTCCalling.EVENT.CALLING_TIMEOUT, this.handleCallTimeout)
				this.trtcCalling.off(this.TRTCCalling.EVENT.NO_RESP, this.handleNoResponse)
				this.trtcCalling.off(this.TRTCCalling.EVENT.CALLING_END, this.handleCallEnd)
				this.trtcCalling.off(this.TRTCCalling.EVENT.USER_VIDEO_AVAILABLE, this.handleUserVideoChange)
				this.trtcCalling.off(this.TRTCCalling.EVENT.USER_AUDIO_AVAILABLE, this.handleUserAudioChange)
			},
			handleError() {
				console.log('Error')
			},
			handleUserVideoChange() {},
			handleUserAudioChange(payload) {
				const _index = this.invitedUserInfo.findIndex(item => item.userID === payload.userID)
				if (_index >= 0) {
					this.invitedUserInfo[_index].isInvitedMicOn = payload.isAudioAvailable
				}
			},
			// 双方，通话已建立, 通话结束
			handleCallEnd({
				userID,
				callEnd
			}) {
				// 自己挂断的要补充消息  被邀请者都无应答时结束
				// 历史消息中没有通话结束
				if (userID === this.userID && this.invitedUserID.length === 0 || this.callingUserList === 0) {
					this.sendMessage(userID, callEnd, this.callingTips.callEnd)
				}
				this.changeState('dialling', false)
				this.isMicOn = true
				this.isCamOn = true
				this.maskShow = false
				this.isStartLocalView = false

			},
			// 自己超时且是邀请发起者，需主动挂断，并通知上层对端无应答
			handleNoResponse({
				sponsor,
				userIDList
			}) { //邀请者
				if (sponsor === this.userID) {
					userIDList.forEach((userID) => {
						this.setCallingstatus(userID)
					})
					if (userIDList.indexOf(this.userID) === -1) { //当超时者是自己时，添加消息
						this.sendMessage(userIDList, '', this.callingTips.callTimeout)
					}
				}
			},
			// 当自己收到对端超时的信令时，或者当我是被邀请者但自己超时了，通知上层通话超时
			// case: A呼叫B，B在线，B超时未响应，B会触发该事件，A也会触发该事件
			handleCallTimeout({
				userIDList
			}) {
				if (this.calling) {
					return
				}
				if (this.userID === this.sponsor) { // 该用户是邀请者
					userIDList.forEach((userID) => {
						this.setCallingstatus(userID) //超时未接听
					})
					return
				}
				//用户是被邀请者
				if (userIDList.indexOf(this.userID) > -1) { //当超时者是自己时，添加消息
					//会话列表切换后发消息
					this.toAccount && this.sendMessage(this.userID, '', this.callingTips.callTimeout)
				}
				this.changeState('isDialled', false)
			},
			handleKickedOut() {
				// 重复登陆，被踢出房间
			},
			// 自己超时且是邀请发起者，需主动挂断，并通知上层对端无应答
			handleNoResponse({
				sponsor,
				userIDList
			}) { //邀请者
				if (sponsor === this.userID) {
					userIDList.forEach((userID) => {
						this.setCallingstatus(userID)
					})
					if (userIDList.indexOf(this.userID) === -1) { // 当超时者是自己时，添加消息
						this.sendMessage(userIDList, '', this.callingTips.callTimeout)
					}
				}

			},
			// 当自己收到对端超时的信令时，或者当我是被邀请者但自己超时了，通知上层通话超时
			// case: A呼叫B，B在线，B超时未响应，B会触发该事件，A也会触发该事件
			handleCallTimeout({
				userIDList
			}) {
				if (this.calling) {
					return
				}
				if (this.userID === this.sponsor) { // 该用户是邀请者
					userIDList.forEach((userID) => {
						this.setCallingstatus(userID) //超时未接听
					})
					return
				}
				//用户是被邀请者
				if (userIDList.indexOf(this.userID) > -1) { //当超时者是自己时，添加消息
					//会话列表切换后发消息
					this.toAccount && this.sendMessage(this.userID, '', this.callingTips.callTimeout)
				}
				this.changeState('isDialled', false)
			},
			handleKickedOut() {},
			// 通知被呼叫方，邀请被取消，未接通
			handleInviterCancel() {
				// 邀请被取消
				this.changeState('isDialled', false)
				uni.showToast({
					title: '通话已取消',
					icon: 'none'
				})
			},
			// 通知呼叫方，对方在忙碌，未接通
			handleInviteeLineBusy({
				sponsor,
				userID
			}) {
				// A call B,C call A, A在忙线， 拒绝通话，对于呼叫者C收到通知，XXX在忙线
				if (sponsor === this.userID) {
					this.setCallingstatus(userID)
					uni.showToast({
						title: '对方忙线',
						icon: 'none'
					})
				}
			},
			setCallingstatus(userID) {
				const _index = this.invitedUserID.indexOf(userID)
				if (_index >= 0) {
					this.invitedUserID.splice(_index, 1)
				}
				if (this.invitedUserID.length === 0) {
					this.changeState('isDialled', false)
					this.changeState('dialling', false)
				}
			},
			// 通知呼叫方，未接通
			//userID:invitee(被邀请者）
			handleInviteeReject({
				userID
			}) {
				if (this.userID === this.sponsor) {
					// 发起者
					this.setCallingstatus(userID)
					uni.showToast({
						title: '用户拒绝通话',
						icon: 'none'
					})
				}
			},
			// 用户离开
			handleUserLeave({
				userID
			}) {
				console.log(this.callType)
				if (this.callType === this.TRTCCalling.CALL_TYPE.AUDIO_CALL) {
					// 语音通话
					const _index = this.invitedUserInfo.findIndex(item => item.userID === userID)
					if (_index >= 0) {
						this.invitedUserInfo.splice(_index, 1)
					}
					return
				}
				const index = this.callingUserList.findIndex(item => item === userID)
				if (index >= 0) {
					this.callingUserList.splice(index, 1)
				}
				this.dialling = true;
				this.calling = false;
				this.isDialled = false;
				this.callingDialog = false
			},
			// 被呼叫  接听方
			async handleNewInvitationReceived(payload) {
				console.log('接听方', payload)
				this.inviteID = payload.inviteID
				this.callingDialog = true
				this.dialling = false;
				this.calling = false;
				this.isDialled = true;
			},
			// 双方建立连接
			handleUserEnter({
				userID
			}) {
				this.changeState('dialling', true)
				this.isAccept()
				// 判断是否为多人通话
				if (this.callingUserList.length >= 2) {
					this.callingType = this.$TIM.TYPES.CONV_GROUP
				}
				if (this.callingUserList.indexOf(userID) === -1) {
					if (this.callType === this.TRTCCalling.CALL_TYPE.AUDIO_CALL) {
						this.getUserAvatar(userID)
					} else {
						this.callingUserList.push(userID)
					}
				}
				if (this.callType === this.TRTCCalling.CALL_TYPE.VIDEO_CALL) {
					this.$nextTick(() => {
						if (!this.isStartLocalView) {
							this.startLocalView() //本地只开启一次
						}
						this.startRemoteView(userID) //远端多次拉流
					})
				}
			},
			/**
			 *  播放本地流
			 */
			startLocalView() {
				this.trtcCalling.startLocalView({
					userID: this.userID,
					videoViewDomID: 'local'
				}).then(() => {
					this.isStartLocalView = true
				})
			},
			async sendMessage(userId, callEnd, callText) {
				let call_text = ''
				userId = Array.isArray(userId) ? userId.join(',') : userId
				let messageData = {
					to: this.toAccount,
					from: userId,
					conversationType: this.currentConversationType,
					payload: {
						data: '',
						description: '',
						extension: ''
					}
				}
				const message = await this.$TIM.createCustomMessage(messageData)
			},
			/**
			 * 播放远端流
			 * @param {Object} userID
			 */
			startRemoteView(userID) {
				this.trtcCalling.startRemoteView({
					userID: userID,
					videoViewDomID: `video-${userID}`
				}).then(() => {

				})
			},
			/**
			 * 获取被呼叫者信息
			 * @param {Object} userID
			 */
			getUserAvatar(userID) {
				const _index = this.invitedUserInfo.findIndex(item => item.userID === userID)
				if (_index >= 0) {
					return
				}
				let _userIDList = [userID]
				let promise = this.tim.getUserProfile({
					userIDList: _userIDList // 请注意：即使只拉取一个用户的资料，也需要用数组类型，例如：userIDList: ['user1']
				})
				promise.then((imResponse) => {
					if (imResponse.data[0]) {
						this.invitedUserInfo.push(imResponse.data[0])
					}
				}).catch(() => {})
			},
			/**
			 *  对方接听自己发起的电话
			 */
			isAccept() {
				clearTimeout(this.timer)
				this.changeState('calling', true)
				clearTimeout(this.hangUpTimer)
				this.resetDuration(0)
				this.start = new Date()
			},
			resetDuration(duration) {
				this.duration = duration
				this.hangUpTimer = setTimeout(() => {
					let now = new Date()
					this.resetDuration(parseInt((now - this.start) / 1000))
				}, 1000)
			},
			/**
			 * 修改状态
			 * @param {Object} state
			 * @param {Object} boolean
			 */
			changeState(state, boolean) {
				let stateList = ['dialling', 'isDialled', 'calling']
				stateList.forEach(item => {
					this[item] = item === state ? boolean : false
				})
				this.$store.commit('UPDATE_ISBUSY', stateList.some(item => this[
					item]))
				// 若stateList 中存在 true , isBusy 为 true
			},
			/**
			 * 是否打开麦克风
			 */
			micHandler() {
				if (this.isMicOn) {
					this.trtcCalling.setMicMute(true)
					this.isMicOn = false
				} else {
					this.trtcCalling.setMicMute(false)
					this.isMicOn = true
				}
			}
		}
	}
</script>

<style lang="scss" scoped>
	@import './index.scss';
</style>
