<template>
	<view class="page">
		<view class="container">
			<text class="noData" v-if="msgList.length === 0">没有对话记录</text>
			<scroll-view :scroll-into-view="scrollIntoView" scroll-y="true" class="msg-list" :enable-flex="true">
				<view v-for="(msg,index) in msgList" :class="{reverse:!msg.isAi}" class="msg-item" :key="index">
					<view class="userInfo">
						<image class="avatar" src="@/static/avatar.png" mode="widthFix"></image>
					</view>
					<view style="flex-direction: column;">
						<text class="create_time">{{toFriendlyTime(msg.create_time)}}</text>
						<view class="content">
							<!-- <uni-ai-msg :content="msg.content"></uni-ai-msg> -->
							<text :selectable="true">{{msg.content}}</text>
							<text v-if="index == msgList.length-1 && msg.isAi && sseIndex" class="blinking-cursor">|</text>
						</view>
					</view>
					<uni-icons v-if="index == msgList.length-1 && !msg.isAi && msg.state != 100 && msgStateIcon(msg)"
						@click="msg.state == -100 ? retriesSendMsg() : ''" :color="msg.state===0?'#999':'#d22'"
						:type="msgStateIcon(msg)" class="msgStateIcon">
					</uni-icons>
				</view>
				<view id="last-msg-item"></view>
			</scroll-view>

			<view class="foot-box">
				<view class="trash">
					<uni-icons @click="clear" type="trash" size="24" color="#888"></uni-icons>
				</view>
				<view class="textarea-box">
					<textarea v-model="content" class="textarea" :auto-height="true" :disabled="inputBoxDisabled"
						:placeholder="placeholderText" :maxlength="-1" placeholder-class="input-placeholder"></textarea>
				</view>
				<button @click="beforeSendMsg" :disabled="inputBoxDisabled || !content" class="send">发送</button>
			</view>
		</view>
		<label class="set-stream">
			<text style="font-size: 12px;">stream:</text>
			<switch style="transform: scale(0.7);" checked="true" :checked="stream" @change="changeStream" />
		</label>
	</view>
</template>

<script>
	import toFriendlyTime from './toFriendlyTime.js';
	export default {
		data() {
			return {
				scrollIntoView: "",
				msgList: [],
				content: "",
				sseIndex: 0,
				stream:false
			}
		},
		computed: {
			inputBoxDisabled() {
				if (this.sseIndex !== 0) {
					return true
				}

				let length = this.msgList.length
				if (length) {
					return !this.msgList[length - 1].isAi
				} else {
					return false
				}
			},
			placeholderText() {
				if (this.inputBoxDisabled) {
					return 'uni-ai正在回复中'
				} else {
					// #ifdef H5
					return window.innerWidth > 960 ? '请输入内容，ctrl + enter 发送' : '请输入要发给uni-ai的内容'
					// #endif
					return '请输入要发给uni-ai的内容'
				}
			}
		},
		watch: {
			msgList(msgList) {
				// uni.setStorageSync('uni-ai-msg', msgList)
			}
		},
		async mounted() {
			// for (let i = 0; i < 15; i++) {
			// 	this.msgList.push({
			// 		isAi: i % 2 == true,
			// 		content: "1-" + i
			// 	})
			// }

			this.msgList = uni.getStorageSync('uni-ai-msg') || []

			// this.msgList.pop()

			console.log('this.msgList', this.msgList);
			this.showLastMsg()

			//获得消息输入框对象
			let adjunctKeydown = false
			const textareaDom = document.querySelector('.textarea-box textarea');
			if (textareaDom) {
				//键盘按下时
				textareaDom.onkeydown = e => {
					// console.log('onkeydown', e.keyCode)
					if ([16, 17, 18, 93].includes(e.keyCode)) {
						//按下了shift ctrl alt windows键
						adjunctKeydown = true;
					}
					if (e.keyCode == 13 && adjunctKeydown) {
						this.beforeSendMsg();
					}
				};
				textareaDom.onkeyup = e => {
					//松开adjunct键
					if ([16, 17, 18, 93].includes(e.keyCode)) {
						adjunctKeydown = false;
					}
				};
			}
		},
		methods: {
			changeStream(e){
				console.log('e',e.detail.value);
				this.stream = e.detail.value
			},
			toFriendlyTime(t) {
				return toFriendlyTime(t)
			},
			retriesSendMsg() {
				this.send()
			},
			beforeSendMsg() {
				if(!this.content){
					return uni.showToast({
						title: '内容不能为空',
						icon: 'none'
					});
				}
				
				this.msgList.push({
					isAi: false,
					content: this.content,
					state: 0,
					create_time: Date.now()
				})
				this.showLastMsg()
				// 清空文本内容
				this.$nextTick(() => {
					this.content = ''
				})
				this.send()
			},
			async send() {
				let messages = []
				// 复制一份，消息列表数据
				let msgs = [...this.msgList]
				// 带总结的消息 index
				let findIndex = [...msgs].reverse().findIndex(item => item.summarize)
				console.log('findIndex', findIndex)
				if (findIndex != -1) {
					let aiSummaryIndex = msgs.length - findIndex - 1
					console.log('aiSummaryIndex', aiSummaryIndex)
					msgs[aiSummaryIndex].content = msgs[aiSummaryIndex].summarize
					// 拿最后一条带直接的消息作为与ai对话的msg body
					msgs = msgs.splice(aiSummaryIndex, msgs.length - 1)
				} else {
					// 如果未总结过就直接从末尾拿10条
					msgs = msgs.splice(-10)
				}

				messages = msgs.map(item => {
					let role = "user"
					if (item.isAi) {
						role = item.summarize ? 'system' : 'assistant'
					}
					return {
						content: item.content,
						role
					}
				})

				console.log('send to ai messages:', messages);
				
				
				let SSEChannel = false;
				if(this.stream){
					SSEChannel = new uniCloud.SSEChannel() // 创建消息通道
					SSEChannel.on('message', (message) => { // 监听message事件
						console.log('on message', message);
						if (this.sseIndex === 0) {
							this.msgList.push({
								isAi: true,
								content: message,
								create_time: Date.now()
							})
							this.showLastMsg()
						} else {
							let length = this.msgList.length,
								lastMsg = this.msgList[length - 1]
							lastMsg.content +=  "\n" + message
							this.msgList.splice(length - 1, 1, lastMsg)
							this.showLastMsg()
						}
						this.sseIndex++
					})
					SSEChannel.on('end', (e) => { // 监听end事件，如果云端执行end时传了message，会在客户端end事件内收到传递的消息
						console.log('on end', e);
						if(e.summarize){
							let length = this.msgList.length,
								lastMsg = this.msgList[length - 1]
							lastMsg.summarize = e.summarize
							this.msgList.splice(length - 1, 1, lastMsg)
						}
						this.sseIndex = 0
						this.showLastMsg()
					})
					await SSEChannel.open() // 等待通道开启
				}
				
				const uniAiChat = uniCloud.importObject("uni-ai-chat")
				uniAiChat.send({
					name: "uni-ai-chat",
					data: {
						messages,
						SSEChannel
					}
				})
				.then(res => {
					let index = this.msgList.length - 1
					let lastItem = this.msgList[index]
					lastItem.state = 100
					this.msgList.splice(index, 1, lastItem)

					if (!SSEChannel) {
						console.log(res, res.result.reply);
						this.msgList.push({
							isAi: true,
							content: res.result.reply,
							summarize: res.result.summarize,
							create_time: Date.now()
						})
						this.showLastMsg()
					}
				})
				.catch(e => {
					console.log(e);
					let index = this.msgList.length - 1
					let lastItem = this.msgList[index]
					lastItem.state = -100
					this.msgList.splice(index, 1, lastItem)

					uni.showModal({
						content: JSON.stringify(e.message),
						showCancel: false
					});
				})
			},
			showLastMsg() {
				this.$nextTick(() => {
					this.scrollIntoView = "last-msg-item"
					this.$nextTick(() => {
						this.scrollIntoView = ""
					})
				})
			},
			msgStateIcon(msg) {
				switch (msg.state) {
					case 0:
						//	发送中
						return 'spinner-cycle'
						break;
					case -100:
						//	发送失败
						return 'refresh-filled'
						break;
					case -200:
						//	禁止发送（内容不合法）
						return 'info-filled'
						break;
					default:
						return false
						break;
				}
			},
			clear() {
				uni.showModal({
					title: "确认要清空聊天记录？",
					content: '本操作不可撤销',
					complete: (e) => {
						if (e.confirm) {
							this.msgList = []
						}
					}
				});

			}
		}
	}
</script>

<style lang="scss">
	/* #ifndef APP-NVUE */
	view,
	textarea,
	button,
	* {
		display: flex;
		box-sizing: border-box;
	}
	/* #endif */

	/* #ifndef APP-NVUE */
	page,
	/* #endif */
	.page,
	.container {
		background-color: #efefef;
		width: 750rpx;
		flex: 1;
		height: calc(100vh - 44px);
		flex-direction: column;
		align-items: center;
	}

	/* #ifndef APP-NVUE */
	.container {
		background-color: #FAFAFA;
	}
	.container,
	.container * {
		max-width: 550px;
	}
	/* #endif */

	.foot-box {
		width: 750rpx;
		display: flex;
		justify-content: space-around;
		align-items: self-start;
		padding: 10px 0px;
		background-color: #FFF;
	}

	.textarea-box {
		padding: 8px;
		background-color: #f9f9f9;
		border-radius: 5px;
	}

	.textarea-box .textarea {
		max-height: 100px;
		width: 460rpx;
		font-size: 14px;
		/* #ifndef APP-NVUE */
		overflow: auto;
		/* #endif */
	}

	/* #ifndef APP-NVUE */
	/*隐藏滚动条*/
	.textarea-box .textarea::-webkit-scrollbar {
		width: 0;
	}
	/* #endif */

	.input-placeholder {
		color: #bbb;
	}

	.trash,
	.send {
		/* border: 1px solid #000; */
		width: 50px;
		height: 30px;
		justify-content: center;
		align-items: center;
	}

	.trash {
		width: 30rpx;
		margin-left: 20rpx;
	}

	.send {
		background-color: #2eaf4d;
		color: #FFF;
		border-radius: 4px;
		display: flex;
		margin: 0;
		padding: 0;
		font-size: 14px;
		margin-right: 20rpx;
	}

	/* #ifndef APP-NVUE */
	.send::after {
		display: none;
	}

	/* #endif */


	.msg-list {
		flex: 1;
		height: 1px;
		width: 750rpx;
	}

	.userInfo {
		flex-direction: column;
	}

	.msg-item {
		position: relative;
		width: 750rpx;
		flex-direction: row;
		padding: 0 15px;
		padding-bottom: 15px;
	}

	.msgStateIcon {
		position: relative;
		top: 5px;
		right: 5px;
		align-self: center;
	}

	.avatar {
		width: 40px;
		border-radius: 2px;
	}

	.create_time {
		font-size: 12px;
		padding: 5px;
		padding-top: 0;
		color: #aaa;
	}

	.content {
		max-width: 500rpx;
		background-color: #FFF;
		border-radius: 5px;
		/* border-top-left-radius: 0; */
		padding: 12px 10px;
		margin-left: 10px;
		/* #ifndef APP-NVUE */
		word-break: break-all;
		user-select: text;
		cursor: text;
		/* #endif */
	}

	/* #ifndef APP-NVUE */
	.content {
		display: inline;
	}
	.content * {
		display: inline;
	}
	/* #endif */


	.reverse {
		flex-direction: row-reverse;
	}

	.reverse .content {
		margin-left: 0;
		margin-right: 10px;
		border-top-left-radius: 15px;
		// border-top-right-radius: 0;
	}

	.reverse-align {
		align-items: flex-end;
	}

	.noData {
		margin-top: 15px;
		text-align: center;
		width: 750rpx;
		color: #aaa;
		font-size: 12px;
		justify-content: center;
	}

	.blinking-cursor {
		color: blue;
		font-weight: bold;
		animation: blinking 1s infinite;
	}
	
	@keyframes blinking {
		from {
			opacity: 1.0;
		}
		to {
			opacity: 0.0;
		}
	}
	
	.set-stream{
		position: fixed;
		right: 0px;
		top: 0;
		z-index: 999;
		padding: 5px;
		justify-content: center;
		align-items: center;
	}
</style>