<!-- pages/aiChat/ai_index -->
<template>
	<view class="chat-container">
		<!-- 状态保持：当AI聊天可见时才显示聊天内容 -->

		<!-- 状态栏占位 -->
		<view class="status-bar-placeholder"></view>

		<!-- 自定义导航栏 -->
		<view class="custom-nav-bar">
			<!-- 左侧：历史记录图标（触发抽屉） -->
			<view class="nav-left" @click="toggleHistoryDrawer">
				<image src="/static/history.svg" mode="aspectFit" class="nav-icon"></image>
			</view>
			<!-- 中间标题 -->
			<view class="nav-title">智水AI辅导员</view>

			<!-- 右侧：新建聊天图标 -->
			<view class="nav-right" @click="newChat">
				<image src="/static/newChat.svg" mode="aspectFit" class="nav-icon"></image>
			</view>
		</view>

		<!-- 消息列表 -->
		<scroll-view scroll-y class="message-list" :scroll-top="scrollTop" scroll-with-animation>
			<block v-for="(item, index) in messages" :key="index">
				<view :class="['message-item', item.sender === 'user' ? 'user-message' : 'ai-message']">
					<!-- 用户/AI头像 -->
					<image class="avatar" :src="item.avatar"></image>
					<view class="message-content">
						<!-- 文字内容 -->
						<view v-if="item.content && item.sender === 'ai'" class="markdown-content"
							v-html="renderMarkdown(item.content)"></view>
						<text v-else-if="item.content">{{ item.content }}</text>
						<!-- 图片内容 -->
						<image v-if="item.image" :src="item.image" class="sent-image"></image>
						<!-- AI 特有内容 -->
						<view v-if="item.sender === 'ai'" class="ai-hint">
							<!-- 引用来源部分 -->
							<view v-if="item.retrieverResources && item.retrieverResources.length"
								class="reference-section">
								<view class="reference-section">
									<text class="reference-title">引用来源：</text>
									<!-- 遍历每个引用资源 -->
									<view v-for="(ref, idx) in item.retrieverResources" :key="idx"
										class="reference-item-wrapper">
										<!-- 可点击的文档名 -->
										<text class="doc-name-link" @click="toggleSingleReference(index, idx)">
											{{ ref.document_name }}
										</text>

										<!-- 展开的详情（仅当前项） -->
										<view v-if="showSingleReference[index] && showSingleReference[index][idx]"
											class="reference-details-item">
											<text class="reference-meta">{{ ref.name }}（{{ ref.document_name }}）</text>
											<text class="reference-content" v-if="ref.content">{{ ref.content }}</text>
										</view>
									</view>
								</view>
							</view>
							<!-- AI操作区域（点赞/点踩） -->
							<view class="ai-actions">
								<text class="ai-text">回答由AI生成</text>
								<view class="icon-group">
									<img src="/static/good.svg" class="btn-icon"
										@click="handleThumbUpClick(item.messageId)" />
									<img src="/static/tread.svg" class="btn-icon"
										@click="handleThumbDownClick(item.messageId)" />
								</view>
							</view>
						</view>
					</view>
				</view>
			</block>
		</scroll-view>

		<!-- 输入框和发送按钮 -->
		<view class="input-container">
			<!-- 历史记录抽屉组件 -->
			<HistoryDrawer :visible="showHistoryDrawer" @close="toggleHistoryDrawer" @item-click="onHistoryItemClick" />

			<!-- 消息输入框 -->
			<input v-model="inputMessage" placeholder="输入消息..." @confirm="sendMessage" confirm-type="send" />
			<!-- 添加图片按钮 -->
			<img src="/static/add.svg" class="add-icon" @click="selectImage" />
			<!-- 发送消息按钮 -->
			<img src="/static/send.svg" class="send-icon" @click="sendMessage" />
		</view>

		<!-- 悬浮按钮：固定在右下角 -->
		<view class="ai-hover" @click="goHome">
			<view class="ai-hover-content">
				<text class="ai-hover-text">AI</text>
			</view>
		</view>
	</view>
</template>

<script>
	/* ========== 依赖 ========== */
	import HistoryDrawer from '@/components/aiChat/HistoryDrawer.vue'; // 历史记录抽屉组件
	import {
		createChatStream
	} from '@/utils/ai_stream.js'; // 流式聊天API
	import MarkdownIt from 'markdown-it'; // Markdown解析器
	import DOMPurify from 'dompurify'; // HTML净化器

	/* DOMPurify 白名单加固 */
	DOMPurify.addHook('afterSanitizeAttributes', node => {
		if (node.tagName === 'A') node.setAttribute('rel', 'noopener noreferrer');
	});

	// 初始化Markdown解析器
	const md = new MarkdownIt({
		html: true,
		linkify: true,
		typographer: true
	});

	/* ========== 配置 ========== */
	const BASE_URL = (function() {
		// #ifdef H5
		return 'http://localhost:8080/dev-api/aitutor/aichat'; // H5环境API地址
		// #endif
		// #ifndef H5
		// return 'http://192.168.31.123:8080/aitutor/aichat'; // 真机调试改成你的电脑 IP
		// #endif
	})();

	/* ========== 组件 ========== */
	export default {
		components: {
			HistoryDrawer
		},
		data() {
			return {
				showHistoryDrawer: false, // 是否显示历史记录抽屉
				inputMessage: '', // 用户输入的消息
				messages: [], // 聊天消息列表
				scrollTop: 0, // 滚动位置
				conversation_id: null, // 当前会话ID
				showSingleReference: {}, // 控制引用来源的显示状态
				currentReader: null, // 当前流式读取器
				/* 新增锁 & 基础信息 */
				sending: false, // 是否正在发送消息
				user: uni.getStorageSync('stuNo') || '', // 用户学号
				userId: uni.getStorageSync('stuId') || '', // 用户ID
				userName: uni.getStorageSync('stuName') || '' // 用户名
			};
		},

		/* ---------- 生命周期 ---------- */
		onLoad() {
			// 页面加载时检查登录状态
			if (!this.user) {
				this.$toast('请先登录');
				setTimeout(() => uni.navigateTo({
					url: '/pages/login/index'
				}), 1500);
				return;
			}
			this.initChat(); // 初始化聊天
		},
		onUnload() {
			// 页面卸载时取消流式读取
			this.currentReader?.cancel?.('页面卸载');
			this.currentReader = null;
		},
		async onPullDownRefresh() {
			// 下拉刷新
			await this.initChat();
			uni.stopPullDownRefresh();
			this.$toast('刷新成功', 'success');
		},

		/* ---------- 方法 ---------- */
		methods: {
			// 返回首页
			goHome() {
				uni.reLaunch({
					url: '/pages/index/index'
				});
			},

			// 切换历史记录抽屉显示状态
			toggleHistoryDrawer() {
				this.showHistoryDrawer = !this.showHistoryDrawer;
			},

			// 渲染Markdown内容
			renderMarkdown(text) {
				return DOMPurify.sanitize(md.render(text || ''));
			},

			/* 轻量 toast 封装 */
			$toast(title, icon = 'none') {
				uni.showToast({
					title,
					icon
				});
			},

			/* 获取历史会话 or 欢迎语 */
			async initChat() {
				if (!this.user) return this.initConversation();
				try {
					// 请求获取用户历史消息
					const res = await uni.request({
						url: BASE_URL + '/getMessagesToUser',
						method: 'POST',
						data: {
							user: this.user
						}
					});
					const data = res.data || {};
					if (data.code === 200 && data.data?.conversationId) {
						// 设置会话ID和消息列表
						this.conversation_id = data.data.conversationId;
						uni.setStorageSync('conversation_id', this.conversation_id);
						this.messages = Array.isArray(data.data.messages) && data.data.messages.length ?
							data.data.messages :
							this.welcomeMessage();
					} else {
						this.initConversation();
					}
				} catch (e) {
					console.error('获取历史失败', e);
					this.$toast('连接失败，使用新会话');
					this.initConversation();
				}
			},

			/* 欢迎语兜底 */
			welcomeMessage() {
				return [{
					sender: 'ai',
					avatar: '/static/AI.png',
					content: '你好！我是您的 AI 小助手，有什么可以帮您？😊',
					retrieverResources: [],
					image: ''
				}];
			},

			// 初始化新会话
			initConversation() {
				uni.removeStorageSync('chatHistory');
				this.conversation_id = null;
				this.messages = this.welcomeMessage();
			},

			/* 发送消息（带并发锁） */
			async sendMessage() {
				const msg = this.inputMessage.trim();
				if (!msg || this.sending) return;
				this.sending = true;

				// 添加用户消息到列表
				this.messages.push({
					sender: 'user',
					avatar: '/static/yonghu.png',
					content: msg,
					image: '',
					messageId: Date.now().toString()
				});
				this.inputMessage = '';

				// 添加AI占位消息
				const aiIdx = this.messages.push({
					sender: 'ai',
					avatar: '/static/AI.png',
					content: '',
					retrieverResources: [],
					image: '',
					messageId: null
				}) - 1;
				this.$set(this.showSingleReference, aiIdx, {});
				this.scrollToBottom();

				try {
					// 创建流式聊天连接
					const {
						stream
					} = createChatStream({
						conversationId: this.conversation_id,
						prompt: msg,
						user: this.user,
						userId: this.userId,
						userName: this.userName
					});
					const {
						reader,
						decoder
					} = await stream;

					let buffer = '';
					// 流式读取数据
					while (true) {
						const {
							done,
							value
						} = await reader.read();
						if (done) break;
						buffer += decoder.decode(value, {
							stream: true
						});
						const lines = buffer.split('\n');
						buffer = lines.pop() || '';

						// 处理每行数据
						for (const l of lines) {
							if (!l.startsWith('data:')) continue;
							const text = l.slice(5).trim();
							if (text === '[DONE]') continue;
							try {
								const json = JSON.parse(text);
								// 处理消息内容
								if (json.event === 'message' && json.answer) {
									this.$set(this.messages[aiIdx], 'content', this.messages[aiIdx].content + json
										.answer);
									this.scrollToBottom();
								}
								// 处理消息结束事件
								if (json.event === 'message_end') {
									if (json['conversation id']) this.conversation_id = json['conversation id'];
									if (json.metadata?.retriever_resources) {
										this.$set(this.messages[aiIdx], 'retrieverResources', json.metadata
											.retriever_resources);
										this.$set(this.messages[aiIdx], 'messageId', json.message_id || Date.now()
											.toString());
									}
								}
							} catch (e) {
								console.warn('JSON 解析失败', text, e);
							}
						}
					}
				} catch (e) {
					console.error('流式请求失败', e);
					this.$set(this.messages[aiIdx], 'content', '抱歉，AI 回复失败，请重试。');
				} finally {
					this.sending = false;
					this.scrollToBottom();
					uni.setStorageSync('chatHistory', this.messages);
				}
			},

			/* 滚动到底部 */
			scrollToBottom() {
				this.$nextTick(() => {
					uni.createSelectorQuery()
						.in(this)
						.select('.message-list')
						.boundingClientRect(rect => {
							this.scrollTop = (rect?.height || 0) + 9999;
						})
						.exec();
				});
			},

			// 切换单个引用来源的显示状态
			toggleSingleReference(msgIdx, refIdx) {
				if (!this.showSingleReference[msgIdx]) this.$set(this.showSingleReference, msgIdx, {});
				const cur = this.showSingleReference[msgIdx][refIdx];
				this.$set(this.showSingleReference[msgIdx], refIdx, !cur);
			},

			// 点赞消息处理
			handleThumbUpClick(id) {
				if (!id) return;
				uni.request({
						url: BASE_URL + '/feedback',
						method: 'POST',
						data: {
							messageId: id,
							action: 1
						}
					}).then(() => this.$toast('点赞成功', 'success'))
					.catch(() => this.$toast('点赞失败'));
			},

			// 点踩消息处理
			handleThumbDownClick(id) {
				if (!id) return;
				uni.request({
						url: BASE_URL + '/feedback',
						method: 'POST',
						data: {
							messageId: id,
							action: 0
						}
					}).then(() => this.$toast('已反馈'))
					.catch(() => this.$toast('反馈失败'));
			},

			// 新建聊天会话
			newChat() {
				this.messages = [];
				this.conversation_id = null;
				uni.removeStorageSync('conversation_id');
				uni.removeStorageSync('chatHistory');
				this.initConversation();
				this.$toast('新聊天已开始');
			},

			/* 选择图片并上传 */
			selectImage() {
				uni.chooseImage({
					count: 1,
					sizeType: ['compressed'], // 压缩
					sourceType: ['album', 'camera'],
					success: res => {
						const temp = res.tempFilePaths[0];
						// 上传图片
						uni.uploadFile({
							url: BASE_URL + '/files/upload',
							filePath: temp,
							name: 'file',
							formData: {
								user: this.user,
								userId: this.userId,
								userName: this.userName
							},
							success: ({
								data
							}) => {
								try {
									const {
										url
									} = JSON.parse(data);
									if (url) {
										// 添加图片消息到列表
										this.messages.push({
											sender: 'user',
											avatar: '/static/yonghu.png',
											content: '',
											image: url,
											messageId: Date.now().toString()
										});
										this.scrollToBottom();
									}
								} catch (e) {
									this.$toast('上传解析失败');
								}
							},
							fail: () => this.$toast('上传失败')
						});
					}
				});
			}
		}
	};
</script>

<style scoped>
	/* 引入全局样式 */
	@import '@/static/scss/ai_index.css';
</style>