<template>
	<view class="ai-page">
		<page-meta :page-style="'overflow:' + (show ? 'hidden' : 'visible')"></page-meta>
		<top @clickLeft="openDrawer" @resetMessage="resetMessage"></top>
		<scroll-view class="content" :scroll-y="true" show-scrollbar="false" scroll-with-animation>
			<front @onSuggestionTap="onQuickAsk" ref="front" />
			<chat :messages="messages" @continueCreate="continueCreate" :isReplying="isReplying" @refresh="refresh"
				@changeShow="changeShow" @changeInputText="changeInputText" @handleVoice="handleVoice"
				:isPlayingVoice="isPlayingVoice" :playSrc="playSrc" />
		</scroll-view>
		<view :style="{ height: marginBottom + 'px', backgroundColor: '#fff' }" />
		<leftDrawer :historyGroups="historyGroups" ref="popup" @changeShow="changeShow"
			@onHistoryItemTap="onHistoryItemTap" @removeFromHistory="removeFromHistory"
			@clearAllHistory="clearAllHistory" />

		<search ref="searchRef" :inputText="inputText" @onSend="onSend" @onQuickAsk="onQuickAsk"
			@changeInputText="changeInputText" :isReplying="isReplying" @handleBreak="handleBreak"
			@changeShow="changeShow" @startRecord="startRecord" />

		<!-- <view class="ai-logo" v-if="isShowRightLogo">
			<image src="../../static/ai.webp" mode="widthFix" style="width: 100%;"></image>
		</view> -->
	</view>
</template>

<script>
	const HISTORY_KEY = "chat_history_groups";
	import {
		getAIResponse,
	} from "@/api/index.js";
	import {
		textToSpeech
	} from '@/utils/utils.js'
	import top from "./top/index.vue";
	import front from "./front/index.vue";
	import chat from "./chat/index.vue";
	import leftDrawer from "./leftDrawer/index.vue";
	import search from "./search/index.vue";
	export default {
		components: {
			top,
			front,
			chat,
			leftDrawer,
			search
		},
		data() {
			return {
				inputText: "",
				messages: [],
				historyGroups: [],
				isLoading: false,
				typewriterTimers: {},
				show: false,
				marginBottom: 0,
				isReplying: false, // 是否正在回复
				breakReplying: false, // 是否打断回复
				replyData: {}, // 回复数据
				isRefresh: false, // 是否重新回复
				audioContext: null,
				isPlayingVoice: false, // 是否正在播放语音
				playSrc: '',
				breakRequestList: [],
				speechIdList: [],
				textToVoiceLoading: false,
				isGetAiLogoMsg: false,
				aiLogoRect: null,
				isShowRightLogo: false
			};
		},
		// onPageScroll(e) {
		// 	if (!this.getAiLogoMsg) {
		// 		this.aiLogoRect = this.$refs.front.getAiLogoMsg();
		// 		this.getAiLogoMsg = true
		// 	}
		// 	if (!this.aiLogoRect) return;
		// 	if (e.scrollTop > (this.aiLogoRect.top + 12)) {
		// 		this.isShowRightLogo = true;
		// 	} else {
		// 		this.isShowRightLogo = false;
		// 	}
		// },
		async mounted() {
			this.loadChatHistory();
			uni.onKeyboardHeightChange((res) => {
				uni.pageScrollTo({
					scrollTop: this.height + res.height,
					duration: 300,
					class: ".content",
				});
			});
			// #ifdef APP-PLUS
			this.$nextTick(() => {
				this.marginBottom = this.$refs.searchRef.getHeight() || 112;
			});
			// #endif
			this.marginBottom = 112;

			this.initAudio();
		},
		beforeDestroy() {
			this.clearTypewriterTimers();
			if (this.isPlayingVoice) {
				this.audioContext.stop();
				this.isPlayingVoice = false;
			}
		},
		methods: {
			// 开始录音后暂停播放语音
			startRecord() {
				if (this.isPlayingVoice && this.audioContext.src) {
					this.audioContext.stop();
					this.isPlayingVoice = false;
				}
			},
			// 点击语音播放暂停
			handleVoice(src) {
				if (!src) return;
				if (this.audioContext.src === src && this.isPlayingVoice) {
					this.isPlayingVoice = false;
					this.audioContext.stop();
					return;
				};
				if (this.audioContext.src === src && !this.isPlayingVoice) {
					this.isPlayingVoice = true;
					this.audioContext.play();
					return;
				};
				if (this.isPlayingVoice) {
					this.audioContext.stop();
				};
				this.isPlayingVoice = true;
				this.audioContext.src = src;
				this.playSrc = src;
				this.audioContext.play();
			},
			// 初始化语音功能， 已经语音部分监听
			initAudio() {
				this.audioContext = uni.createInnerAudioContext()
				this.audioContext.onCanplay((e) => {
					let items = this.messages.find(item => item.src && item.src === this.audioContext.src);
					if (!items) return;
					items.duration = this.audioContext.duration;
					// this.isPlayingVoice = true;
					// this.audioContext.play()
				});
				this.audioContext.onEnded(res => {
					this.isPlayingVoice = false
				})
			},
			// 处理百度返回arraybuff格式的语音
			getSpeech(speechStr) {
				let self = this;
				this.textToVoiceLoading = true;
				let startTime = Date.now();
				return new Promise((resolve) => {
					textToSpeech(speechStr).then(audioData => {
						this.playSrc = audioData;
						this.audioContext.src = audioData;
						resolve(true)
					})
				})
			},
			// 重新回复
			refresh() {
				this.messages.splice(this.messages.length - 1, 1);
				this.inputText = this.messages[this.messages.length - 1].content;
				this.isRefresh = true;
				this.onSend();
			},
			// 继续生成
			continueCreate() {
				this.breakReplying = false;
				this.isReplying = true;
				if (!this.isLoading) {
					this.messages[this.messages.length - 1].isBreak = false;
					this.replyAction(this.replyData, true)
				} else {
					this.messages.splice(this.messages.length - 1, 1);
					this.messages.push({
						id: this.loadingId,
						role: "assistant",
						loading: true,
					});
				}
			},
			// 中断回复
			handleBreak() {
				if (this.isLoading) {
					const loadingIdx = this.messages.findIndex((m) => m.id === this.loadingId);
					if (loadingIdx > -1) this.messages.splice(loadingIdx, 1);
					// 5. 添加回复 + 打字机
					const replyId = this.baseId + 1;
					this.messages.push({
						id: replyId,
						role: "assistant",
						type: "text",
						content: '',
						displayText: "已停止",
						isBreak: true
					});
					this.isReplying = false;
					this.scrollToBottom();
				}
				this.breakReplying = true;
			},
			// 新建对话
			resetMessage() {
				if (this.messages.length === 0) return;
				if (this.isLoading) {
					this.breakRequestList.push({
						requestId: this.requestId
					});
				};
				if (this.textToVoiceLoading) {
					this.speechIdList.push({
						speedId: this.speedId
					})
				};
				if (this.isPlayingVoice) {
					this.isPlayingVoice = false;
					this.audioContext.stop();
				}
				this.clearTypewriterTimers();
				this.isReplying = false;
				this.messages = [];
			},
			// 清理所有打字机定时器
			clearTypewriterTimers() {
				Object.values(this.typewriterTimers).forEach((timer) => {
					if (timer) clearInterval(timer);
				});
				this.typewriterTimers = {};
			},
			// 修改输入框文本
			changeInputText(text) {
				this.inputText = text;
			},
			//打开历史记录
			openDrawer() {
				this.$refs.popup.open();
			},
			// 点击历史记录搜索
			onHistoryItemTap(text) {
				this.inputText = text;
				this.onSend();
				this.$refs.popup.close();
			},
			// 聊天页面禁止滚动
			changeShow(e) {
				this.show = e;
			},
			//  删除历史记录
			removeFromHistory(text) {
				let groups = uni.getStorageSync(HISTORY_KEY)?.groups || [];
				groups.forEach((group) => {
					group.items = group.items.filter((item) => item !== text);
				});
				groups = groups.filter((g) => g.items.length > 0);
				this.historyGroups = groups;
				uni.setStorageSync(HISTORY_KEY, {
					groups,
					updatedAt: Date.now(),
				});
			},
			//  清除全部历史记录
			clearAllHistory() {
				uni.showModal({
					title: "清除全部",
					content: "将删除所有对话记录，此操作不可恢复",
					success: (res) => {
						if (res.confirm) {
							uni.removeStorageSync(HISTORY_KEY);
							this.historyGroups = [];
							uni.showToast({
								title: "已清除",
								icon: "success",
							});
						}
					},
				});
			},

			formatDate(date) {
				const y = date.getFullYear();
				const m = String(date.getMonth() + 1).padStart(2, "0");
				const d = String(date.getDate()).padStart(2, "0");
				return `${y}年${m}月${d}日`;
			},
			// 加载历史记录
			loadChatHistory() {
				try {
					const data = uni.getStorageSync(HISTORY_KEY);
					if (data && Array.isArray(data.groups)) {
						this.historyGroups = data.groups;
					} else {
						this.historyGroups = [];
					}
				} catch (e) {
					this.historyGroups = [];
				}
			},
			// 添加历史记录
			addToHistory(text) {
				let groups = uni.getStorageSync(HISTORY_KEY)?.groups || [];
				const today = this.formatDate(new Date());
				let todayGroup = groups.find((g) => g.date === today);

				if (!todayGroup) {
					todayGroup = {
						date: today,
						items: [],
					};
					groups.unshift(todayGroup);
				}

				if (!todayGroup.items.includes(text)) {
					todayGroup.items.unshift(text);
				}

				// 限制大小
				if (todayGroup.items.length > 50)
					todayGroup.items = todayGroup.items.slice(0, 50);
				if (groups.length > 30) groups = groups.slice(0, 30);

				this.historyGroups = groups;
				uni.setStorageSync(HISTORY_KEY, {
					groups,
					updatedAt: Date.now(),
				});
			},
			// 快速提问
			onQuickAsk(text) {
				this.inputText = text;
				this.onSend();
			},
			// 发送消息
			async onSend(inputType = "text", inputContent = "", duration = undefined) {
				if (this.isReplying) return;
				const text = (this.inputText || "").trim();
				if (!text || this.isLoading) return;
				this.baseId = Date.now();
				if (!this.isRefresh) {
					// 1. 用户消息
					this.messages.push({
						id: this.baseId,
						role: "user",
						type: "text",
						content: text,
						inputType: typeof inputType === "string" ? inputType : "text",
						inputContent,
						duration,
					});
				}
				// 2. loading 消息
				this.loadingId = this.baseId + 0.5;
				this.messages.push({
					id: this.loadingId,
					role: "assistant",
					loading: true,
				});
				this.inputText = "";
				this.isReplying = true;
				this.isLoading = true;
				this.isRefresh = false;
				this.scrollToBottom();
				this.addToHistory(text);
				if (this.isPlayingVoice) {
					this.audioContext.stop();
					this.isPlayingVoice = false;
				};
				let requestId = Date.now();
				this.requestId = requestId;
				// 3. 真正等待 AI 回复
				const reply = await getAIResponse({
					message: text,
				});
				this.isLoading = false;
				let requestIndex = this.breakRequestList.findIndex(item => item.requestId === requestId)
				if (requestIndex > -1) {
					this.breakRequestList = this.breakRequestList.splice(requestIndex, -1)
					return;
				}
				this.replyData = reply;
				if (this.breakReplying) {
					this.breakReplying = false;
					return;
				}
				this.replyAction(reply)
			},
			async replyAction(reply, isContinue) {
				let content = ''
				// 判断请求是否出错
				if (reply.errMsg) {
					content = `请求出错: 系统异常`
				} else {
					content = reply;
				};
				let result;
				let speechId = Date.now();
				this.speechId = speechId;
				if (this.$store.state.set.replyPattern === '1' && !this.messages[this.messages.length - 1].src && !
					reply.errMsg) {

					result = await this.getSpeech(reply);
				};
				if (result) {
					let speechIndex = this.speechIdList.findIndex(item => item.speechId === speechId)
					if (speechIndex > -1) {
						this.speechIdList = this.speechIdList.splice(speechIndex, -1)
						return;
					}
					if (result) {
						this.isPlayingVoice = true;
						this.audioContext.play();
					};
				}
				// 4. 移除 loading
				const loadingIdx = this.messages.findIndex((m) => m.id === this.loadingId);
				if (loadingIdx > -1) this.messages.splice(loadingIdx, 1);
				// 5. 添加回复 + 打字机
				const replyId = this.baseId + 1;
				if (!isContinue) {
					this.messages.push({
						id: replyId,
						role: "assistant",
						type: "text",
						content,
						displayText: "",
						src: (this.audioContext.src && this.$store.state.set.replyPattern === '1') ? JSON
							.parse(JSON.stringify(this.audioContext.src)) : null,
						duration: null
					});
				} else {
					this.audioContext.play();
					this.isPlayingVoice = true;
				}
				this.$nextTick(() => this.scrollToBottom());
				this.typewriter(replyId, content);
			},
			// 打印机效果，并清除加载动画
			typewriter(messageId, fullText) {
				const msg = this.messages.find((m) => m.id === messageId);
				if (!msg) return;
				// 清理之前的定时器（如果存在）
				if (this.typewriterTimers[messageId]) {
					clearInterval(this.typewriterTimers[messageId]);
				}
				let index = msg.displayText.length;
				msg.displayText = fullText.substring(0, index + 1);
				index += 1;
				const speed = 50; // 每个字符间隔50ms
				const timer = setInterval(() => {
					// 是否中断
					if (this.breakReplying) {
						clearInterval(timer);
						delete this.typewriterTimers[messageId];
						msg.isBreak = true;
						this.isReplying = false;
						this.breakReplying = false
						this.isLoading = false;
						this.isPlayingVoice = false;
						this.audioContext.stop();
						this.scrollToBottom();
					}
					if (index < fullText.length) {
						msg.displayText = fullText.substring(0, index + 1);
						index++;
						this.scrollToBottom();
					} else {
						clearInterval(timer);
						delete this.typewriterTimers[messageId];
						// 完成后使用完整文本
						msg.displayText = fullText;
						this.isReplying = false;
						this.breakReplying = false;
						this.$nextTick(() => {
							this.scrollToBottom();
						});
					}
				}, speed);
				this.typewriterTimers[messageId] = timer;
			},
			// 滚动到底部
			scrollToBottom() {
				let self = this;
				this.$nextTick(() => {
					uni
						.createSelectorQuery()
						.select(".content")
						.boundingClientRect((rect) => {
							if (self.height !== rect.height) {
								self.height = rect.height;
								uni.pageScrollTo({
									scrollTop: rect.height,
									duration: 300,
									class: ".content",
								});
							}
						})
						.exec();
				});
			},
		},
	};
</script>

<style scoped>
	::v-deep .uni-nav-bar-text {
		font-size: 18px !important;
	}

	::v-deeo .uni-navbar--border {
		border-bottom: 1px solid #fff !important;
	}

	.ai-page {
		display: flex;
		flex-direction: column;
		background: #fff;
	}

	.content {
		flex: 1;
		padding: 16px 12px 0px 12px;
		background-color: #fff;
		width: 100%;
		box-sizing: border-box;
	}

	.ai-logo {
		width: 60px;
		position: fixed;
		top: 50%;
		right: 10px;
		z-index: 999999999;
	}
</style>