<template>
	<div class="flex flex-col py-3 rounded-lg group">
		<template v-if="(message.role as string) === 'assistant'">
			<!-- Assistant message -->
			<div class="relative chat chat-start" v-if="message.content || message.reasoning_content">
				<div class="chat-image avatar">
					<div v-if="selectedKnowledge?.avatarUrl?.includes('svg')" v-html="selectedKnowledge?.avatarUrl"></div>
					<div class="w-[40px] h-[40px] rounded-full overflow-hidden" v-else>
						<img
							:src="selectedKnowledge?.avatarUrl?.includes('http') ? selectedKnowledge?.avatarUrl : baseURL + selectedKnowledge?.avatarUrl"
							class="object-cover w-full h-full"
						/>
					</div>
				</div>
				<div class="flex items-center mb-1 ml-6 space-x-2 chat-header">
					<span class="font-medium text-gray-800 dark:text-gray-200">AI 助手</span>
					<time class="text-xs opacity-70">{{ message.time }}</time>
					<div class="flex items-center space-x-1">
						<el-button
							@click="handleCopyText(message.content)"
							class="!p-1 h-6"
							text
							icon="CopyDocument"
							v-if="message.content"
							type="primary"
						></el-button>
						<audio-player
							ref="audioPlayerRef"
							:text="message.content"
							v-if="message === messageList[messageList.length - 1] && message.content && messageList.length > 1"
						/>
						<el-button
							@click="handleRegenerate()"
							class="!p-1 h-6"
							text
							icon="Refresh"
							v-if="message === messageList[messageList.length - 1] && message.content && messageList.length > 1"
							type="primary"
						></el-button>
					</div>
				</div>
				<div class="max-w-3xl bg-white rounded-lg dark:bg-gray-800 dark:border-gray-700">
					<div class="flex flex-col gap-3 p-4" :class="{ 'md:flex-row': message.content && message.chartId && isWideScreen }">
						<!-- Reasoning content collapsible panel -->
						<div
							v-if="message.reasoning_content"
							:class="[
								'bg-gray-50 rounded-lg border border-gray-200 collapse collapse-arrow dark:bg-gray-800 dark:border-gray-700',
								collapseStates[message.time || ''] === false ? 'collapse-close' : 'collapse-open',
							]"
						>
							<input type="checkbox" class="peer" @change="collapseStates[message.time || ''] = !collapseStates[message.time || '']" />
							<div
								class="text-sm font-medium text-gray-700 collapse-title dark:text-gray-300 peer-checked:bg-gray-100 dark:peer-checked:bg-gray-700/50 hover:bg-gray-100 dark:hover:bg-gray-700/50"
							>
								<div class="flex gap-2 items-center">
									<svg
										xmlns="http://www.w3.org/2000/svg"
										class="w-4 h-4 text-gray-500 dark:text-gray-400"
										fill="none"
										viewBox="0 0 24 24"
										stroke="currentColor"
									>
										<path
											stroke-linecap="round"
											stroke-linejoin="round"
											stroke-width="2"
											d="M9.663 17h4.673M12 3v1m6.364 1.636l-.707.707M21 12h-1M4 12H3m3.343-5.657l-.707-.707m2.828 9.9a5 5 0 117.072 0l-.548.547A3.374 3.374 0 0014 18.469V19a2 2 0 11-4 0v-.531c0-.895-.356-1.754-.988-2.386l-.548-.547z"
										/>
									</svg>
									已深度思考（用时 {{ message.thinking_time || '0' }} 秒）
								</div>
							</div>
							<div class="collapse-content bg-gray-50/50 dark:bg-gray-800/50 peer-checked:bg-gray-100 dark:peer-checked:bg-gray-700/50">
								<div class="pt-4 text-gray-600 whitespace-pre-wrap dark:text-gray-300">
									{{ message.reasoning_content }}
								</div>
							</div>
						</div>

						<!-- Tool info collapsible panel -->
						<div
							v-if="message.toolInfo"
							:class="[
								'bg-gray-50 rounded-lg border border-gray-200 collapse collapse-arrow dark:bg-gray-800 dark:border-gray-700',
								collapseStates['tool_' + index] === true ? 'collapse-open' : 'collapse-close',
							]"
						>
							<input 
								type="checkbox" 
								class="peer" 
								@change="collapseStates['tool_' + index] = !collapseStates['tool_' + index]" 
							/>
							<div
								class="text-sm font-medium text-gray-700 collapse-title dark:text-gray-300 peer-checked:bg-gray-100 dark:peer-checked:bg-gray-700/50 hover:bg-gray-100 dark:hover:bg-gray-700/50"
							>
								<div class="flex gap-2 items-center">
									<svg
										xmlns="http://www.w3.org/2000/svg"
										class="w-4 h-4 text-gray-500 dark:text-gray-400"
										fill="none"
										viewBox="0 0 24 24"
										stroke="currentColor"
									>
										<path
											stroke-linecap="round"
											stroke-linejoin="round"
											stroke-width="2"
											d="M10.325 4.317c.426-1.756 2.924-1.756 3.35 0a1.724 1.724 0 002.573 1.066c1.543-.94 3.31.826 2.37 2.37a1.724 1.724 0 001.065 2.572c1.756.426 1.756 2.924 0 3.35a1.724 1.724 0 00-1.066 2.573c.94 1.543-.826 3.31-2.37 2.37a1.724 1.724 0 00-2.572 1.065c-.426 1.756-2.924 1.756-3.35 0a1.724 1.724 0 00-2.573-1.066c-1.543.94-3.31-.826-2.37-2.37a1.724 1.724 0 00-1.065-2.572c-1.756-.426-1.756-2.924 0-3.35a1.724 1.724 0 001.066-2.573c-.94-1.543.826-3.31 2.37-2.37.996.608 2.296.07 2.572-1.065z"
										/>
										<path
											stroke-linecap="round"
											stroke-linejoin="round"
											stroke-width="2"
											d="M15 12a3 3 0 11-6 0 3 3 0 016 0z"
										/>
									</svg>
									工具调用：{{ message.toolInfo.name }}
								</div>
							</div>
							<div class="collapse-content bg-gray-50/50 dark:bg-gray-800/50 peer-checked:bg-gray-100 dark:peer-checked:bg-gray-700/50">
								<div class="pt-4">
									<div class="mb-2 text-sm font-medium text-gray-700 dark:text-gray-300">工具名称：</div>
									<div class="mb-4 px-3 py-2 bg-white rounded border text-gray-800 dark:bg-gray-800 dark:border-gray-600 dark:text-gray-200">
										{{ message.toolInfo.name }}
									</div>
									<div class="mb-2 text-sm font-medium text-gray-700 dark:text-gray-300">调用参数：</div>
									<div class="px-3 py-2 bg-white rounded border text-gray-800 dark:bg-gray-800 dark:border-gray-600 dark:text-gray-200">
										<pre class="whitespace-pre-wrap text-sm">{{ getFormattedToolParams(message.toolInfo.params) }}</pre>
									</div>
								</div>
							</div>
						</div>

						<!-- Main content -->
						<div
							ref="contentContainer"
							class="relative text-gray-800 dark:text-gray-200"
							v-if="message.content"
							:class="{ 'md:flex-1 md:max-w-[60%]': message.chartId && isWideScreen }"
						>
							<MdRenderer v-if="selectedKnowledge.id !== '-4'" :source="message.content" class="w-full" />
							<MindMap v-else :text="message.content" :id="message.time || ''" />
							<router-link
								v-if="message.path"
								:to="message.path"
								class="inline-flex absolute top-1 right-1 items-center text-sm text-blue-600 transition-colors duration-200 shrink-0 hover:text-blue-800 dark:text-blue-400 dark:hover:text-blue-300"
							>
								<svg xmlns="http://www.w3.org/2000/svg" class="mr-1 w-4 h-4" fill="none" viewBox="0 0 24 24" stroke="currentColor">
									<path
										stroke-linecap="round"
										stroke-linejoin="round"
										stroke-width="2"
										d="M10 6H6a2 2 0 00-2 2v10a2 2 0 002 2h10a2 2 0 002-2v-4M14 4h6m0 0v6m0-6L10 14"
									/>
								</svg>
								一键跳转
							</router-link>
						</div>

						<!-- Chart display for chartId messages -->
						<div
							v-if="message.chartId"
							class="overflow-hidden relative flex-1 mt-6 w-full bg-white rounded-lg border border-gray-200 shadow-sm dark:bg-gray-800 dark:border-gray-700 chart-container"
							:class="{ 'md:mt-0 md:min-w-[500px] md:max-w-[40%]': message.content && isWideScreen }"
							style="min-height: 300px; height: 50vh; max-height: 500px"
						>
							<!-- 图表标题栏 -->
							<div class="flex justify-between items-center p-3 border-b border-gray-200 dark:border-gray-700">
								<div class="flex items-center">
									<svg xmlns="http://www.w3.org/2000/svg" class="mr-2 w-5 h-5 text-blue-500" fill="none" viewBox="0 0 24 24" stroke="currentColor">
										<path
											stroke-linecap="round"
											stroke-linejoin="round"
											stroke-width="2"
											d="M9 19v-6a2 2 0 00-2-2H5a2 2 0 00-2 2v6a2 2 0 002 2h2a2 2 0 002-2zm0 0V9a2 2 0 012-2h2a2 2 0 012 2v10m-6 0a2 2 0 002 2h2a2 2 0 002-2m0 0V5a2 2 0 012-2h2a2 2 0 012 2v14a2 2 0 01-2 2h-2a2 2 0 01-2-2z"
										/>
									</svg>
									<span class="font-medium text-gray-700 dark:text-gray-300">数据可视化</span>
								</div>
							</div>

							<!-- 图表内容 -->
							<div class="p-3 h-[calc(100%-48px)]">
								<v-chart v-if="chartOption" class="w-[500px] h-full" :option="chartOption" autoresize />

								<!-- 图表加载状态 -->
								<div v-else class="flex justify-center items-center h-full">
									<div class="flex flex-col items-center">
										<span class="mb-2 text-gray-600 dark:text-gray-300">图表加载中...</span>
										<div class="flex space-x-2">
											<span class="text-blue-500 loading loading-spinner loading-md"></span>
										</div>
									</div>
								</div>
							</div>
						</div>
					</div>
				</div>

				<div
					class="flex gap-2 items-center ml-6 chat-footer"
					v-if="
						(message.extLinks && message.extLinks.length > 0) ||
						(message === messageList[messageList.length - 1] && messageList.length > 1 && !isFinish)
					"
				>
					<!-- Stop button -->
					<el-button
						v-if="message === messageList[messageList.length - 1] && messageList.length > 1 && !isFinish"
						@click="handleStopGenerate()"
						text
						icon="VideoPause"
						type="primary"
						class="!bg-white dark:!bg-gray-700 !shadow-md !rounded-full !p-2"
					></el-button>

					<!-- Reference materials -->
					<div v-if="message.extLinks && message.extLinks.length > 0" class="flex-1 px-3 rounded-md dark:bg-gray-700/40">
						<div class="flex flex-wrap gap-2 items-center text-xs">
							<span class="font-medium text-gray-600 dark:text-gray-300">参考资料</span>
							<div class="flex flex-wrap gap-1.5">
								<el-tag
									v-for="(link, linkIndex) in message.extLinks"
									:key="linkIndex"
									size="small"
									effect="plain"
									class="!border-0 !bg-gray-100 dark:!bg-gray-600 !text-gray-700 dark:!text-gray-300"
								>
									{{ link.name }}
								</el-tag>
							</div>

							<!-- Rating -->
							<div v-if="message.extLinks[0].distance" class="flex items-center ml-auto space-x-1">
								<div class="tooltip tooltip-left" :data-tip="`相关度: ${Number(message.extLinks[0].distance).toFixed(2)}`">
									<div class="rating rating-xs">
										<input
											v-for="n in 5"
											:key="n"
											type="radio"
											:name="'rating' + index"
											class="mask mask-star-2 bg-blue-400/80 dark:bg-blue-500/80"
											:checked="Math.round(message.extLinks[0].distance * 5) === n"
											disabled
										/>
									</div>
								</div>
							</div>
						</div>
					</div>
				</div>
			</div>

			<!-- Loading indicator for LLM responses -->
			<div class="flex" v-if="!message.content && !message.reasoning_content">
				<div class="flex justify-center items-center mt-2 ml-12 text-center">
					<span class="mx-0.5 loading loading-ball loading-xs dark:bg-blue-500"></span>
					<span class="mx-0.5 loading loading-ball loading-sm dark:bg-blue-500"></span>
					<span class="mx-0.5 loading loading-ball loading-md dark:bg-blue-500"></span>
					<span class="mx-0.5 loading loading-ball loading-lg dark:bg-blue-500"></span>
				</div>
			</div>
		</template>

		<template v-else-if="(message.role as string) === 'user'">
			<!-- User message -->
			<div class="chat chat-end">
				<div class="chat-image avatar">
					<div class="w-[40px] h-[40px] rounded-full overflow-hidden">
						<img
							alt="User avatar"
							:src="roleAlias[message.role]?.includes('http') ? roleAlias[message.role] : baseURL + roleAlias[message.role]"
							class="object-cover w-full h-full"
						/>
					</div>
				</div>
				<div class="flex justify-end items-center mb-1 space-x-2 chat-header">
					<time class="text-xs opacity-70">{{ message.time }}</time>
					<span class="font-medium text-gray-800 dark:text-gray-200">{{ userInfos.user.username }}</span>
				</div>
				<div class="max-w-3xl bg-white rounded-lg dark:bg-gray-800 dark:border-gray-700">
					<div class="p-4 text-gray-800 dark:text-gray-200">
						<MdRenderer v-if="message.content" :source="message.content || ''" class="w-full" />
					</div>
				</div>
			</div>
		</template>
	</div>
</template>

<script setup lang="ts">
import { storeToRefs } from 'pinia';
import MdRenderer from '/@/components/MdRenderer/MdRenderer.vue';
import MindMap from '/@/components/MindMap/index.vue';
import AudioPlayer from './widgets/audio-player.vue';
import VChart from 'vue-echarts';
import { useIntervalFn, useMediaQuery } from '@vueuse/core';
import type { ChatMessage, Dataset } from '../ts/index';
import { useUserInfo } from '/@/stores/userInfo';
import { getChartData } from '../ts/gpt';

import { use } from 'echarts/core';
import { BarChart } from 'echarts/charts';
import { LineChart } from 'echarts/charts';
import { PieChart } from 'echarts/charts';
import { GridComponent } from 'echarts/components';
import { CanvasRenderer } from 'echarts/renderers';

use([GridComponent, BarChart, LineChart, PieChart, CanvasRenderer]);

const stores = useUserInfo();
const { userInfos } = storeToRefs(stores);
const baseURL = import.meta.env.VITE_API_URL || '';

const props = defineProps({
	message: {
		type: Object as () => ChatMessage,
		required: true,
	},
	index: {
		type: Number,
		required: true,
	},
	selectedKnowledge: {
		type: Object as () => Dataset,
		required: true,
	},
	messageList: {
		type: Array as () => ChatMessage[],
		required: true,
	},
	isFinish: {
		type: Boolean,
		default: true,
	},
	roleAlias: {
		type: Object,
		required: true,
	},
	collapseStates: {
		type: Object,
		required: true,
	},
});

const emit = defineEmits(['copyText', 'regenerate', 'stopGenerate']);
const audioPlayerRef = ref();
const chartOption = ref(null);
const isPolling = ref(false); // 是否正在轮询中
const isWideScreen = ref(useMediaQuery('(min-width: 1024px)')); // 判断是否为宽屏
const pollAttempts = ref(0); // 轮询尝试次数计数器

// Make content and chart display side by side on wide screens
// 使内容和图表在宽屏上并排显示
const contentContainer = ref<HTMLElement | null>(null);

// Function to fetch chart data
// 获取图表数据的函数
const fetchChartData = async (chartId: string) => {
	try {
		const { data } = await getChartData(chartId);
		if (data) {
			chartOption.value = JSON.parse(data);

			// 如果成功获取到有效数据，停止轮询
			if (chartOption.value) {
				isPolling.value = false;
				pause();
			}
		}
	} catch (error) {
		// 静默处理错误
	}

	// 限制最多轮询10次
	pollAttempts.value++;
	if (pollAttempts.value >= 10) {
		isPolling.value = false;
		pause(); // 达到最大轮询次数后停止
	}
};

// Setup interval to poll for chart data
// 设置轮询图表数据的定时器
const { pause, resume } = useIntervalFn(
	() => {
		if (props.message.chartId) {
			fetchChartData(props.message.chartId);
		}
	},
	2000, // Poll every 2 seconds 每2秒轮询一次
	{ immediate: false, immediateCallback: false }
);

// Watch for chartId changes to start/stop polling
// 监听chartId变化以开始/停止轮询
watch(
	() => props.message.chartId,
	(newChartId) => {
		if (newChartId && !isPolling.value) {
			isPolling.value = true;
			pollAttempts.value = 0; // 重置计数器
			// Fetch immediately and then start polling
			// 立即获取数据然后开始轮询
			fetchChartData(newChartId);
			resume();
		} else if (!newChartId && isPolling.value) {
			isPolling.value = false;
			pause(); // 当没有chartId时停止轮询
		}
	},
	{ immediate: true } // 立即执行
);

// Stop polling when component is unmounted
// 组件卸载时停止轮询
onUnmounted(() => {
	pause();
});

const handleCopyText = (content: string) => {
	emit('copyText', content);
};

const handleRegenerate = () => {
	emit('regenerate');
};

const handleStopGenerate = () => {
	// 停止生成的同时也停止轮询
	if (isPolling.value) {
		isPolling.value = false;
		pause();
	}
	emit('stopGenerate');
};

// 格式化工具参数，使 JSON 更易读
const getFormattedToolParams = (params: string): string => {
	try {
		const parsed = JSON.parse(params);
		return JSON.stringify(parsed, null, 2);
	} catch (error) {
		return params; // 如果不是有效的 JSON，则返回原始字符串
	}
};
</script>
