<template>
	<cover-view>
		<template v-if="openCommentStatus==2">
			<text v-for="(item, index) in activeDanmus" :key="item.commentId" class="danmu-item danmuMove"
				:style="{
				  top: item.top + 'px',
				  ...item.style,
				  'animation-duration': '8s'
				 }" @animationend="animationend(item,index)">
				{{ item.content }}
			</text>
		</template>
		<view class="container-body" id="msglist" v-if="openCommentStatus==1">
			<view class="listbox" v-for="(item, index) in msgs" :key="index" :id="'view' + index">
				<text :class="userId&&item.userId == userId?'list-name my':'list-name'">
					{{userId&&item.userId == userId ? '我' : item.nickName||'--'}}:
				</text>
				<text class="list-con">{{item.content||''}}</text>
			</view>
			<view class="empty" v-if="msgs&&msgs.length==0">暂无评论~</view>
		</view>
	</cover-view>
</template>

<script>
	import { saveMsg,revokeMsg,getComments} from "@/api/course.js"
	export default {
		props: {
			height:{
				type: String,
				default:'0px'
			},
			urlOption:{
				type: Object,
				default:{}
			},
			time:{
				type: [String,Number],
				default: 0
			},
			viewCommentNum:{
				type: [String,Number],
				default: 200
			},
			openCommentStatus:{
				type: [String,Number],
				default: 3
			},
			//  用户自己开启关闭弹幕展示 1，展示弹幕，0 关闭的弹幕
			showDanmu:{
				type: [String,Number],
				default: 1
			},
		},
		data() {
			return {
				statusBarHeight: uni.getSystemInfoSync().statusBarHeight,
				scrollTop: 0,
				inputText:"",
				isSocketOpen:false,
				socket:null,
				isSend:true,
				commentList:[],
				msgs: [],
				pageNum: 1,
				pageSize: 10,
				userInfo: {},
				userId: '',
				pingpangTimes:null,
				// 弹幕
				danmuList: [],
				tracks:[],
				activeDanmus:[],
				flagTime: 0,
				danmuItemStyle:{
					color: '#ffffff',
					fontSize: '16px',
					border: 'solid 1px #ffffff',
					borderRadius: '5px',
					padding: '2px 2px',
					backgroundColor: 'rgba(255, 255, 255, 0.1)'
				},
				ctx: null,
				danmuIndex:{}
			}
		},
		mounted() {
			this.getComments()
			this.getUser();
			this.initTracks()
			if(!this.socket || !this.isSocketOpen) {
				this.initSocket()
			}
		},
		methods: {
			back() {
				uni.navigateBack()
			},
			getUser() {
				const userInfo = uni.getStorageSync('userInfo');
				if(userInfo&&JSON.stringify(userInfo)!='{}') {
					this.userInfo = JSON.parse(userInfo)
					this.userId = this.userInfo.userId || ''
				}else {
					this.userInfo = {}
					this.userId = ''
				}
			},
			getComments() {
				let that = this
				getComments({
					pageNum: this.openCommentStatus==2 ? 1 : this.pageNum,
					pageSize: this.openCommentStatus==2 ? this.viewCommentNum : this.pageSize,
					courseId: this.urlOption.courseId,
					videoId: this.urlOption.videoId,
					openCommentStatus: this.openCommentStatus
				}).then(res=>{
					if(res.code==200){
						if(this.openCommentStatus==2) {
							this.danmuList = res.data.list.map(item=>({
								commentId: item.commentId,
								content: item.content,
								time: item.time || this.time,
								color: "#FFFFFF",
								mode: item.mode || "scroll",
								top: null,
								style: {
									color: item.isColor==1 ? item.color || this.danmuItemStyle.color : this.danmuItemStyle.color,//是否彩色1是0否
									fontSize: item.fontSize || this.danmuItemStyle.fontSize, 
									padding: this.danmuItemStyle.padding,
									border:this.userInfo.userId ==item.userId ? item.color ? `solid 1px ${item.color}`: this.danmuItemStyle.border : 'none',
									borderRadius: this.userInfo.userId==item.userId ? this.danmuItemStyle.borderRadius : 0,
									backgroundColor: this.userInfo.userId==item.userId ? this.danmuItemStyle.backgroundColor : 'transparent'
								},
							}))
							this.initDanmuIndex()
							that.$emit('getMore',0)
						} else if(this.openCommentStatus==1) {
							let list = res.data.list.reverse()
							if (that.pageNum == 1) {
								that.commentList = list; 
								that.handleScrollBottom();
							} else {
								that.commentList = that.commentList.concat(list);
							}
							that.msgs = [...list,...that.msgs]
							if(that.commentList.length >= res.data.total || that.commentList.length >= Number(this.viewCommentNum||200)) {
								that.$emit('getMore',1)
							} else {
								this.pageNum++
								that.$emit('getMore',0)
							}
						} else {
							that.danmuList = []
							that.danmuIndex = {};
							that.commentList = [];
							that.msgs = that.msgs;
							that.$emit('getMore',0);
						}
					}
					else{
						that.danmuList = []
						that.danmuIndex = {};
						that.commentList = [];
						that.msgs = that.msgs;
						that.$emit('getMore',0);
					}
				})
			},
			saveMsg() {
				if (this.inputText == "" || this.inputText.trim() == "") {
					uni.showToast({
						title: '请输入评论',
						icon: "none"
					})
					return;
				}
				if (!this.isSend) {
					return;
				}
				const param = {
					userId: this.userId || '',
					userType: 2, // 1-管理员，2-用户
					courseId: this.urlOption.courseId,
					videoId: this.urlOption.videoId,
					type:1, // 评论类型 1：评论，2：回复，目前没有回复，默认传1就行了
					content: this.inputText,
					time: this.time,
					fontSize: '16px',
					mode: "scroll",
					color: "#ffffff",
				}
				saveMsg(param).then(res=>{
					if(res.code == 200) {
						const status = res.status ? 0 : 1
						this.sendMsg(param,status);
					} else {
						uni.showToast({
							title: res.msg,
							icon: "none"
						})
					}
				})
			},
			handleInput(val) {
				this.inputText = val
				if(!this.isSocketOpen) {
					// 重新发起会话
					this.initSocket('reStart')
				} else {
					this.saveMsg();
				}
			},
			handleScrollBottom() {
				setTimeout(() => {
					const query = uni.createSelectorQuery().in(this);
					query.select('#msglist')
						.boundingClientRect((res) => {
							if(res) {
								const scrollH = res.height;
								this.scrollTop = res.height;
								this.$emit('getScrollTop',this.scrollTop)
							}
						}).exec();
				},500);
			},
			initSocket(type) { 
				//创建一个socket连接
				var userId = this.userInfo.userId;
				var that = this;
				if (this.socket) {
					this.socket.close()
					this.socket = null;
				}
				this.socket = uni.connectSocket({
					url: getApp().globalData.wsUrl + "/app/webSocket/" + userId,
					multiple: true,
					success: res => {
						console.log('WebSocket连接已打开1！');
						that.isSocketOpen = true
						// 保持心跳
						if(that.pingpangTimes) {
							clearInterval(that.pingpangTimes)
							that.pingpangTimes= null
						}
						that.pingpangTimes=setInterval(()=>{
							let data={
								userId: that.userId || '',
								userType: 2, // 1-管理员，2-用户
								courseId: that.urlOption.courseId,
								videoId: that.urlOption.videoId,
								type:1, // 评论类型 1：评论，2：回复，目前没有回复，默认传1就行了
								// msg: that.inputText,
								cmd:'heartbeat'
							};
							that.socket.send({
								data: JSON.stringify(data),
								success: () => {
									// console.log('WebSocket发送心条数据！');
								},
								fail: () => {
									that.isSocketOpen=false
								}
							});
						},15000)
					},
					error: res => {
						console.log(res)
					},
				})
				this.socket.onMessage((res) => {
					// console.log("收到消息parse",JSON.parse(res.data))
					const redata = JSON.parse(res.data);
					if(redata.cmd=="heartbeat"){
						  //心跳
						  // console.log("heartbeat")
					}else if(redata.cmd=="sendMsg"){
						that.isSend=true;
						that.addMsg(redata);
					}
				})
				//监听socket打开
				this.socket.onOpen(() => {
					console.log('WebSocket连接已打开2！');
					that.isSocketOpen = true
					that.isSend = true;
					if(type=='reStart') {
						// 重连的时候重新发消息
						this.saveMsg()
					}
				})
				//监听socket关闭
				this.socket.onClose(() => {
					that.isSocketOpen = false
					that.socket = null
					console.log('WebSocket连接已关闭！');
					if(that.pingpangTimes) {
						clearInterval(that.pingpangTimes)
						that.pingpangTimes= null
					}
				})
				//监听socket错误
				this.socket.onError((err) => {
					console.log("socket err：",err)
					that.isSocketOpen = false
					that.socket = null
					if(that.pingpangTimes) {
						clearInterval(that.pingpangTimes)
						that.pingpangTimes= null
					}
				})
			},
			sendMsg(param,status) {
				if(status == 1) {
					this.addMsg({msg: param.content,time: param.time},2)
					return
				}
				if (this.isSocketOpen) {
					var userId = this.userInfo.userId;
					var data = {
						userId: this.userId || '',
						userType: 2, // 1-管理员，2-用户
						courseId: this.urlOption.courseId,
						videoId: this.urlOption.videoId,
						type:1, // 评论类型 1：评论，2：回复，目前没有回复，默认传1就行了
						msg: param.content,
						cmd: 'sendMsg',
						time: param.time,
						fontSize: '16px',
						mode: "scroll",
						color: "#ffffff",
						nickName: this.userInfo.nickName
					};
					this.socket.send({
						data: JSON.stringify(data),
						success: () => {
							console.log("发送成功")
							this.isSend = false;
						},
						fail: () => {
							console.log("发送失败")
						}
					});
			
				}
			
			},
			addMsg(data,type) {
				let obj  = {}
				if (type==2) {
					obj = {
						content: data.msg,
						courseId: this.urlOption.courseId,
						type: 1,
						userId: this.userId,
						userType: 2,
						videoId: this.urlOption.videoId,
						nickName: '',
						time: data.time,
						fontSize: data.fontSize,
						mode: data.mode,
						color: data.color,
						nickName: this.userInfo.nickName
					}
				} else {
					obj = {
						content: data.msg,
						courseId: this.urlOption.courseId,
						type: data.type,
						userId: data.userId,
						userType: data.userType,
						videoId: this.urlOption.videoId,
						nickName: data.nickName,
						time: data.time,
						fontSize: data.fontSize,
						mode: data.mode,
						color: data.color,
						nickName: data.nickName
					}
				}
				if(this.openCommentStatus == 1){
					this.msgs.push(obj)
					this.handleScrollBottom();
				} else if(this.openCommentStatus == 2) {
					this.addDanmuMsg(obj)
				}
				this.inputText = ""
				this.$emit("setInputText")
			},
			addDanmuMsg(content) {
				const id = content.userId +'_' + new Date().getTime()
				const mystyle = {
					color: content.color || this.danmuItemStyle.color,
					fontSize: content.fontSize || this.danmuItemStyle.fontSize,
					border: content.color ? `solid 1px ${content.color}`: this.danmuItemStyle.border,
					borderRadius: this.danmuItemStyle.borderRadius,
					padding: this.danmuItemStyle.padding,
					backgroundColor: this.danmuItemStyle.backgroundColor
				}
				const otherstyle = {
					color: content.color || this.danmuItemStyle.color,
					fontSize: content.fontSize || this.danmuItemStyle.fontSize,
					padding: this.danmuItemStyle.padding,
				}
				const mode = content.mode || "scroll"
				const obj = {
					commentId: content.commentId || id,
					userId: content.userId,
					content: content.content,
					time: this.flagTime + 1,
					color: content.color || this.danmuItemStyle.color,
					style: this.userInfo.userId == content.userId ? mystyle : otherstyle,
					top: null
				}
				if(this.showDanmu == 0) return

				// 如果danmuList超过最大大小，移除旧的弹幕
				const maxDanmuListSize = 10000; // 设置最大大小
				if (this.danmuList.length >= maxDanmuListSize) {
					this.danmuList.shift(); // 移除最旧的弹幕
				}
				this.danmuList.push(obj);
			
				// 更新索引
				if (!this.danmuIndex[obj.time]) {
					this.danmuIndex[obj.time] = [];
				}
				this.danmuIndex[obj.time].push(obj);
			},
			closeWSocket() {
				if(this.socket!=null){
					this.socket.close()
				}
				if(this.pingpangTimes) {
					clearInterval(this.pingpangTimes)
					this.pingpangTimes= null
				}
			},
			initTracks() {
				this.tracks = [];
				const trackHeight = 22; // 每行高度
				const trackCount = 3;
				for (let i = 0; i < trackCount; i++) {
					this.tracks.push({
						top: i * trackHeight + 10,
						isFree: true,
						releaseTime: 0 // 轨道释放时间
					});
				}
			},
			// 获取字体高度
			getTextWidth(content) {
				if (!this.ctx) {
					this.ctx = uni.createCanvasContext('myCanvas')
				}
				const metrics = this.ctx.measureText(content)
				return Math.ceil(metrics.width)
			},
			// 分配轨道
			getFreeTrack(item) {
				const screenWidth = uni.getSystemInfoSync().screenWidth;
				const width = this.getTextWidth(item.content);
				const passWidth = width + screenWidth;
				const duration = 8; // 持续时间（秒）
				const currentTime = Date.now();
			
				for (let i = 0; i < this.tracks.length; i++) {
					if (this.tracks[i].isFree || this.tracks[i].releaseTime <= currentTime) {
						this.tracks[i].isFree = false;
						this.tracks[i].releaseTime = currentTime + Math.ceil(duration * 1000 / passWidth * width) + 1000;
						return this.tracks[i].top;
					}
				}
			
				// 无可用轨道
				if (this.userInfo.userId && item.userId == this.userInfo.userId) {
					// console.log("自己发的弹幕");
					let trackHeight = this.tracks[this.tracks.length - 1].top;
					return Math.random() * trackHeight + 16; // 自己发的弹幕随机高度
				} else {
					// console.log("无可用轨道");
					return 'abandon';
				}
			},
			// 初始化时建立索引
			initDanmuIndex() {
			    this.danmuIndex = {};
			    this.danmuList.forEach((item) => {
			        if (!this.danmuIndex[item.time]) {
			            this.danmuIndex[item.time] = [];
			        }
			        this.danmuIndex[item.time].push(item);
			    });
			},
			// 检测并激活弹幕
			checkDanmu(flagTime) {
				this.flagTime = flagTime;
				if(this.showDanmu == 0) return;
				const newDanmus = this.danmuList.filter((item) => Math.abs(item.time - this.flagTime) < 1);
				// 分配轨道高度
				const aliveNewDanmus = newDanmus.map((item) => {
					if (!item.top) {
						item.top = this.getFreeTrack(item);
					}
					return item;
				}).filter((item) => item.top !== 'abandon');
				// 添加到活跃列表
				this.activeDanmus = [...this.activeDanmus, ...aliveNewDanmus];
			},
			animationend(moveItem, i) {
				// 移除动画结束的弹幕（性能优化）
				this.activeDanmus = this.activeDanmus.filter((item) => item.commentId !== moveItem.commentId)
			},
		},
		beforeDestroy() {
			if(this.socket!=null){
				this.socket.close()
			}
			if(this.pingpangTimes) {
				clearInterval(this.pingpangTimes)
				this.pingpangTimes= null
			}
		}
	}
</script>

<style scoped lang="scss">
	@mixin u-flex($flexD, $alignI, $justifyC) {
		display: flex;
		flex-direction: $flexD;
		align-items: $alignI;
		justify-content: $justifyC;
	}
	.empty {
		@include u-flex(row, center, center);
		padding: 24rpx 50rpx;
		color: #999999;
	}
	.listbox {
		white-space: pre-wrap;
		letter-spacing: 1px;
		margin-bottom: 16rpx;
	}
	.list-name {
		flex-shrink: 0;
		font-family: PingFang SC, PingFang SC;
		font-weight: 600;
		font-size: 28rpx;
		color: #222222;
		margin-right: 16rpx;
	}
	.my {
		color: #FF5C03;
	}
	.list-con {
		font-family: PingFang SC, PingFang SC;
		font-size: 28rpx;
		color: #222222;
	}
	.nav-bar {
		position: fixed;
		z-index: 9999;
		top: 0;
		left: 0;
		width: 100%;
		overflow: hidden;

		.nav-bg {
			width: 100%;
			height: 100%;
			position: absolute;
			left: 0;
			top: 0;
			z-index: 1;
			background-color: #fff;
		}

		&-box {
			position: relative;
			padding: 0 24rpx;
			@include u-flex(row, center, flex-start);
			height: 88rpx;
			box-sizing: border-box;
			z-index: 3;
		}

		&-left {
			width: 100%;
			@include u-flex(row, center, flex-start);
			overflow: hidden;

			image {
				flex-shrink: 0;
				width: 64rpx;
				height: 64rpx;
				border-radius: 12rpx 12rpx 12rpx 12rpx;
			}
		}

		&-name {
			font-family: PingFang SC, PingFang SC;
			font-weight: 600;
			font-size: 28rpx;
			color: #222222;
		}

		&-head {
			flex: 1;
			overflow: hidden;
			margin-left: 22rpx;
			margin-right: 22rpx;
			font-family: PingFang SC, PingFang SC;
			font-weight: 400;
			font-size: 23rpx;
			color: #999999;
		}
	}

	.page-bg {
		position: absolute;
		top: 0;
		left: 0;
	}

	.container-body {
		padding: 32rpx 30rpx;
		box-sizing: border-box;
	}

	.TUI-message-list {
		width: 100%;
		box-sizing: border-box;
	}
	.chatinput {
		position: fixed;
		left: 32rpx;
		right: 32rpx;
		z-index: 999;
		bottom: calc(var(--window-bottom) + 24rpx);
		height: 96rpx;
		background-color: green;
		background: #FFFFFF;
		box-shadow: 0rpx 8rpx 21rpx 0rpx rgba(0, 0, 0, 0.1);
		border-radius: 24rpx 24rpx 24rpx 24rpx;
		@include u-flex(row, center, center);
		padding: 0 24rpx;
		box-sizing: border-box;
		.uni-input {
			flex: 1;
			margin-right: 32rpx;
			font-size: 30rpx;
		}
	
		.send {
			font-family: PingFang SC, PingFang SC;
			font-weight: 400;
			font-size: 28rpx;
			color: #FFFFFF !important;
			flex-shrink: 0;
			padding: 0 20rpx;
			height: 72rpx;
			background: #FF5C03 !important;
			border-radius: 8rpx 8rpx 8rpx 8rpx;
			&::after {
				border: none;
			}
		}
	}
	.danmu-item {
		position: absolute;
		top: 0;
		white-space: nowrap;
		font-size: 16px;
		height: 20px;
		display: inline-flex;
		box-sizing: border-box;
		align-items: center;
	}
	.danmuMove {
		// animation: mymove 8s linear forwards;
		// animation-duration: 8s;
		animation-timing-function: linear;
		animation-delay: 0s;
		animation-iteration-count: 1;
		animation-direction: normal;
		animation-fill-mode: forwards;
		animation-play-state: running;
		animation-name: mymove;
		will-change: transform;
	}
	
	@keyframes mymove {
		from {
			transform: translateX(100vw);
		}
	
		to {
			transform: translateX(-100%);
		}
	}
</style>