<template>
	<div class="agent-container flex flex-col">
		<div class="agent-header flex align-center space-between">
			<div class="header-title-wrapper">
				<div class="agent-title">{{ props.title }}</div>
				<div class="agent-name">AI Assistant 1.0</div>
			</div>
			<!-- <SvgIcon name="equal" color="#0d0d0d" size="24" /> -->
		</div>
		<div class="agent-body flex-1 flex flex-col">
			<List ref="listRef" :message-list="messageList" />
			<Input
				ref="inputRef"
				is-agent-mode
				:generating="isGenerating"
				@send="handleSendMessage"
				@pause="handlePause"
			/>
		</div>
	</div>
</template>

<script setup lang="ts">
	import {
		ref,
		reactive,
		computed,
		onUnmounted,
		onMounted,
		nextTick,
		watch,
		onActivated
	} from 'vue'
	import List from './List.vue'
	import Input from '../../components/Input.vue'
	import { chatUrl } from '@/api/agent'
	import type { AgentParamsType } from '@/api/agent'
	import { useUserInfoStore, useProjectStore, useAgentStore } from '@/stores'
	import MyEvent from '@/utils/myEvent'
	import { areaList } from '@/utils/area'
	import { useI18n } from 'vue-i18n'
	import { useRoute } from 'vue-router'
	import { ElMessage } from 'element-plus'
	import { createStyleOptions, createTypeOptions } from '../../components/input/options'
	import type { OptionItem, ParameterTag } from '../../components/input/types'

	const { t } = useI18n()
	const route = useRoute()

	const userStore = useUserInfoStore()
	const agentStore = useAgentStore()
	const projectStore = useProjectStore()

	const reportsContent = ref('')
	const isGeneratingReport = ref(false)

	const emits = defineEmits(['update:sketchList', 'setTitle'])
	const props = withDefaults(
		defineProps<{
			title: string
		}>(),
		{
			title: 'Retro Sofa Sketch'
		}
	)

	const messageList = ref([])

	const listRef = ref()
	const inputRef = ref()
	const isGenerating = ref(false)
	const isPaused = ref(false) // 标记是否为主动暂停
	const params = reactive<AgentParamsType>({
		projectID: route.params.id as string,
		message: '',
		token: userStore.state.token,
		versionID: '',
		needSuggestion: false,
		useReport: false,
		configParams: {
			type: '',
			region: '',
			style: ''
		},
		imageUrlList: [],
		quotaUrl: []
	})

	const sketchList = ref([])
	const typeOptions = createTypeOptions()
	const areaOptions = areaList
	const styleOptions = createStyleOptions()

	const getTranslatedOptionLabel = (options: OptionItem[], value?: string) => {
		if (!value) return ''
		const option = options.find((item) => item.value === value)
		return option ? t(option.label) : value
	}

	const getOptionLabel = (options: OptionItem[], value?: string) => {
		if (!value) return ''
		return options.find((item) => item.value === value)?.label || value
	}

	const getProjectParameterTags = (project: any): ParameterTag[] => {
		const type = project?.type || ''
		const region = project?.region || project?.area || ''
		const style = project?.style || ''
		const tags: ParameterTag[] = []

		if (type) {
			tags.push({
				kind: 'type',
				label: getTranslatedOptionLabel(typeOptions, type)
			})
		}
		if (region) {
			tags.push({
				kind: 'area',
				label: getTranslatedOptionLabel(areaOptions, region)
			})
		}
		if (style) {
			tags.push({
				kind: 'style',
				label: getOptionLabel(styleOptions, style)
			})
		}

		return tags
	}

	const applyProjectParameterTags = (messages: any[], project: any) => {
		const parameterTags = getProjectParameterTags(project)
		if (parameterTags.length === 0) return

		const firstUserMessage = messages.find((item) => item.isUser || item.role === 'user')
		if (firstUserMessage) {
			firstUserMessage.parameterTags = parameterTags
		}
	}

	watch(
		sketchList,
		(newVal) => {
			emits('update:sketchList', newVal)
		},
		{ deep: true }
	)

	const handleReset = () => {
		messageList.value = []
		sketchList.value = []
		params.versionID = ''
		params.imageUrlList = []
		params.quotaUrl = []
		params.needSuggestion = false
		params.useReport = false
		params.configParams = {
			type: '',
			region: '',
			style: ''
		}
		isGenerating.value = false
	}

	// 每次请求时创建新的 AbortController
	let abort: AbortController

	const createAbortController = () => {
		// 如果已有未完成的中止，先中止它
		if (abort) {
			abort.abort()
		}
		abort = new AbortController()
		return abort
	}

	let debouncedWebAddress: string[] | null = null
	let openUrlsTimer: ReturnType<typeof setTimeout> | null = null
	const triggerOpenUrls = (list: string[]) => {
		debouncedWebAddress = list
		if (openUrlsTimer) clearTimeout(openUrlsTimer)
		openUrlsTimer = setTimeout(() => {
			if (debouncedWebAddress) {
				MyEvent.emit('openUrls', debouncedWebAddress)
				debouncedWebAddress = null
			}
		}, 400)
	}

	onUnmounted(() => {
		// abort?.abort()
		if (openUrlsTimer) clearTimeout(openUrlsTimer)
		MyEvent.remove('resetAgent', handleReset)
	})

	onMounted(() => {
		MyEvent.add('resetAgent', handleReset)
		// 检查 store 中是否有初始项目数据
		const initialData = agentStore.getInitialProjectData
		if (initialData) {
			// 等待页面渲染完成后自动发送初始消息
			params.configParams = {
				type: initialData.type || '',
				region: initialData.area || '',
				style: initialData.style || '',
				temperature: 0.7
			}
			params.needSuggestion = initialData.needSuggestion || false
			params.useReport = initialData.useReport
			handleSendMessage({
				text: initialData.text,
				images: initialData.images,
				useReport: initialData.useReport,
				tempImages: initialData.tempImages,
				quoteList: initialData.quoteList,
				parameterTags: initialData.parameterTags || []
			})
			// 更新 configParams

			// 清空初始数据
			agentStore.clearInitialProjectData()
		}
	})

	// 用于存储不在页面显示但是仍进行中的对话信息
	const newQueue = ref<{
		nodeId?: string
		name?: string
	}>({})
	onActivated(() => {
		if (newQueue.value.nodeId) {
			projectStore.setProject({ nodeId: newQueue.value.nodeId })
		}
		if (newQueue.value.name) {
			MyEvent.emit('newTitle', {
				title: newQueue.value.name,
				id: params.projectID
			})
		}
		if (newQueue.value.newSketch) {
			mergeUniqueKeys(sketchList.value, newQueue.value.newSketch)
			MyEvent.emit('OpenSketch', params.projectID)
		}
		newQueue.value = {}
	})

	const handleSendMessage = async (
		message: {
			text: string
			images: Array<{ url: string; name: string }>
			tempImages: any[]
			useReport: boolean
			quoteList: Array<string>
			parameterTags?: Array<{ kind: string; label: string }>
		},
		skipUserMessage = false
	) => {
		isPaused.value = false
		isGenerating.value = true
		params.message = message.text
		if (Object.prototype.hasOwnProperty.call(message, 'useReport')) {
			params.useReport = message.useReport
		}

		params.imageUrlList = message.images || []
		params.quotaUrl = message.quoteList || []
		// 如果不是重新生成模式，则添加用户消息到列表
		if (!skipUserMessage) {
			messageList.value.push({
				id: messageList.value.length + 1,
				text: message.text,
				isUser: true,
				imageUrls: message.tempImages.concat(message.quoteList),
				parameterTags: message.parameterTags || []
			})
		}

		// Add AI loading message
		const aiMessage = reactive({
			id: messageList.value.length + 1,
			text: '',
			isUser: false,
			sessionId: route.params.id as string,
			loading: true,
			thinking: false,
			thinkingText: '',
			streaming: true
		})
		messageList.value.push(aiMessage)

		// 创建新的 AbortController
		const abortController = createAbortController()

		// console.log('token---', params.token, '参数---', params)
		params.projectID = route.params.id as string
		try {
			const urlParams = new URLSearchParams<AgentParamsType>({
				...params,
				// configParams: JSON.stringify(params.configParams)
				configParams: JSON.stringify({
					type: params.configParams.type || '',
					region: params.configParams.region || '',
					style: params.configParams.style || '',
					temperature: params.configParams.temperature
				})
			})
			const BASEURL = import.meta.env.VITE_APP_URL

			const response = await fetch(`${BASEURL}${chatUrl}?${urlParams.toString()}`, {
				method: 'GET',
				signal: abortController.signal,
				keepalive: true
			})

			// 检查响应内容类型，判断是否为流式响应
			const contentType = response.headers.get('content-type') || ''
			const isStreamResponse =
				contentType.includes('text/event-stream') || contentType.includes('stream')

			if (!response.ok) {
				// 非流式错误响应，使用 text() 读取错误信息
				const errorText = await response.text()
				console.error('请求错误:', errorText)
				if (!isPaused.value) {
					aiMessage.text = '发送失败,请重试'
				}
				aiMessage.streaming = false
				aiMessage.loading = false
				isGenerating.value = false
				return
			}

			// 不是流式响应，使用 text()读取错误信息
			if (!isStreamResponse) {
				const text = await response.text()
				try {
					const errorData = JSON.parse(text)
					console.error('非流式响应:', errorData)
				} catch (e) {
					console.error('非流式响应文本:', text)
				}
				if (!isPaused.value) {
					aiMessage.text = '发送失败,请重试'
				}
				aiMessage.streaming = false
				aiMessage.loading = false
				isGenerating.value = false
				return
			}

			// 流式响应处理
			let contentBody = ''
			let buffer = ''
			const reader = response.body?.getReader()
			if (!reader) throw new Error('无法获取流读取器')

			const decoder = new TextDecoder()
			let previousEventName = '' // 记录上一个事件名称
			let hasReportStarted = false // 标记 report 是否已经开始

			let hasSketchEvent = false
			let hasReportEvent = false
			try {
				let flag = true
				while (flag) {
					const { done, value } = await reader.read()
					if (done) {
						if (hasSketchEvent) {
							aiMessage.text += `<slot slot-name="sketch"></slot>`
						}
						if (hasReportEvent) {
							aiMessage.text += `<slot slot-name="card" title="Report" content="Report"></slot>`
						}

						aiMessage.streaming = false
						aiMessage.loading = false
						isGenerating.value = false
						flag = false
						break
					}

					buffer += decoder.decode(value, { stream: true })

					// 优先按空行拆分事件块（SSE标准）
					let events = buffer.split(/\n\n/)
					buffer = events.pop() // 保留不完整块

					for (let event of events) {
						if (!event.trim()) continue

						const eventName = event
							.split(/\n/)
							.find((line) => line.startsWith('event:'))
							?.replace(/^event:\s*/, '')
							?.trim()

						if (!hasReportStarted && eventName === 'report') {
							isGeneratingReport.value = true
							hasReportEvent = true
							// contentBody += `<slot slot-name="card" title="Report" content="Report"></slot>`
							hasReportStarted = true
							ElMessage.success(t('agent.generatingReport'))
						}

						if (
							previousEventName === 'report' &&
							eventName !== 'report' &&
							reportsContent.value
						) {
							isGeneratingReport.value = false
							aiMessage.report = reportsContent.value
						}

						previousEventName = eventName

						// console.log('eventName:', eventName, 'event:', event)

						// 根据事件名称精确判断，而不是用 includes
						if (eventName === 'error') {
							aiMessage.text = '出现错误,请重试'
							aiMessage.streaming = false
							aiMessage.loading = false
							isGenerating.value = false
							flag = false
							break
						}
						if (eventName === 'todo') {
							continue
						}

						let isNodeIdEvent = eventName === 'nodeId'

						let hasSketch = eventName === 'sketchIDAndUrl'

						const dataLines = event
							.split(/\n/)
							.filter((line) => line.startsWith('data:'))
							.map((line) => line.replace(/^data:\s*/, ''))
							.filter((content) => content.startsWith('{') || content.startsWith('['))
						// console.log('dataLInes', dataLines)
						if (isNodeIdEvent) {
							const versionID = event
								.split(/\n/)
								.filter((line) => line.startsWith('data:'))
								.map((line) => line.replace(/^data:\s*/, ''))[0]
							params.versionID = versionID
							if (String(aiMessage.sessionId) === String(projectStore.state.id)) {
								projectStore.setProject({ nodeId: versionID })
							} else {
								newQueue.value.nodeId = versionID
							}
						}

						if (eventName === 'tool') {
							MyEvent.emit('loading-sketch', sketchList.value.length)
						}

						if (dataLines.length === 0) continue
						const jsonText = dataLines.join('\n')

						try {
							const jsonData = JSON.parse(jsonText)
							// console.log('jsonData', jsonData)
							if (jsonData.webAddress) {
								const parsed = JSON.parse(jsonData.webAddress)
								aiMessage.webAddress = parsed
								aiMessage.loading = false
								if (String(aiMessage.sessionId) === String(projectStore.state.id)) {
									triggerOpenUrls(parsed)
								}
							}
							if (jsonData.title) {
								if (aiMessage.sessionId === projectStore.state.id) {
									emits('setTitle', jsonData.title)
								} else {
									newQueue.value.name = jsonData.title
								}

								MyEvent.emit('newTitle', {
									title: jsonData.title,
									id: params.projectID
								})
							}

							if (hasSketch) {
								hasSketchEvent = true
								let tempArr = []

								if (String(params.projectID) === String(projectStore.state.id)) {
									mergeUniqueKeys(sketchList.value, jsonData)
									MyEvent.emit('OpenSketch', params.projectID)
								} else {
									mergeUniqueKeys(tempArr, jsonData)
									newQueue.value.newSketch = tempArr
								}
							}
							if (eventName === 'reportName' || eventName === 'reportTitle') {
								aiMessage.reportName = jsonData.reportName || jsonData.reportTitle
							}
							if (eventName === 'report') {
								reportsContent.value += jsonData.report
							} else {
								if (jsonData.reasoning) {
									aiMessage.thinking = true
									aiMessage.loading = false
									aiMessage.thinkingText += jsonData.reasoning
								} else {
									aiMessage.thinking = false
									if (
										jsonData.content &&
										jsonData.content.length > 0 &&
										jsonData.type !== 'end'
									) {
										contentBody += jsonData.content
										aiMessage.text = contentBody
										aiMessage.loading = false
									}
								}
							}
							if (jsonData.type === 'end') {
								aiMessage.streaming = false
								aiMessage.loading = false
								isGenerating.value = false
								flag = false
								break
							}
						} catch (e) {
							// 检查是否为纯文本 [DONE]
							if (jsonText.trim() === '[DONE]') {
								console.log('结束-----------------------')
								aiMessage.text = contentBody
								aiMessage.streaming = false
								aiMessage.loading = false
								isGenerating.value = false
								flag = false
								break
							}
							// JSON 不完整：保留到下一次循环
							if (!jsonText.trim().endsWith('}')) {
								buffer = 'data: ' + jsonText // 重新放回缓存
								continue
							} else {
								console.warn('⚠️ JSON 格式错误，跳过:', jsonText)
							}
						}

						// 更新上一个事件名称
						previousEventName = eventName
					}
				}
			} catch (error) {
				console.error('流式传输错误:', error)
				if (!isPaused.value) {
					aiMessage.text = '发送失败,请重试'
				}
				aiMessage.streaming = false
				aiMessage.loading = false
				isGenerating.value = false
			} finally {
				reader.releaseLock()
			}
		} catch (error) {
			console.error('fetch请求失败:', error)
			if (!isPaused.value) {
				aiMessage.text = '发送失败,请重试'
			}
			aiMessage.streaming = false
			aiMessage.loading = false
			isGenerating.value = false
		}
	}

	const handlePause = () => {
		isPaused.value = true
		isGenerating.value = false
		abort?.abort()
		MyEvent.emit('stopChat')
	}

	// const handleRegenerate = async (aiMessage: any) => {
	// 	// 找到当前 AI 消息在列表中的索引
	// 	const aiIndex = messageList.value.findIndex((msg) => msg.id === aiMessage.id)
	// 	if (aiIndex === -1) return

	// 	// 找到对应的用户消息（AI 消息前面的最近一条用户消息）
	// 	let userMessage = null
	// 	for (let i = aiIndex - 1; i >= 0; i--) {
	// 		if (messageList.value[i].isUser) {
	// 			userMessage = messageList.value[i]
	// 			break
	// 		}
	// 	}
	// 	if (!userMessage) return

	// 	// 删除当前的 AI 回复消息
	// 	messageList.value.splice(aiIndex, 1)

	// 	// 重新调用 API（跳过用户消息添加，因为用户消息已存在）
	// 	await handleSendMessage(
	// 		{
	// 			text: userMessage.text,
	// 			images: userMessage.images || []
	// 		},
	// 		true
	// 	)
	// }

	// 处理对话列表，将连续的 assistant 消息合并为一条
	const processDialogue = (dialogue, startIndex, existingImgList, sessionId) => {
		if (!dialogue || dialogue.length === 0) return []

		const result = []
		let i = startIndex

		while (i < dialogue.length) {
			const item = dialogue[i]
			if (item.role === 'user') {
				result.push({
					...item,
					text: item.content,
					isUser: true,
					id: result.length + 1,
					sessionId: sessionId
				})
				i++
			} else if (item.role === 'assistant') {
				let combinedContent = item.content || ''
				let combinedThinkingText = item.reasoning || ''
				let combinedImageUrl = item.image_url || null
				let reportName = item.reportName || null
				let webAddress = item.webAddress || null
				let combinedReport = item.report || ''
				let hasReportSlot = !!item.report
				let hasUrlSlot = !!item.webAddress

				let j = i + 1
				while (j < dialogue.length && dialogue[j].role === 'assistant') {
					const next = dialogue[j]
					combinedContent += next.content || ''
					combinedThinkingText += next.reasoning || ''
					combinedReport += next.report || ''
					if (next.image_url) combinedImageUrl = next.image_url
					if (next.reportName) reportName = next.reportName
					if (next.report) hasReportSlot = true
					if (next.webAddress) {
						webAddress = next.webAddress
						hasUrlSlot = true
					}
					j++
				}

				if (hasUrlSlot) {
					combinedContent += `<slot slot-name="url"></slot>`
				}
				if (hasReportSlot) {
					combinedContent += `<slot slot-name="card" title="Report" content="Report"></slot>`
				}

				result.push({
					...item,
					reportName,
					report: combinedReport,
					content: combinedContent,
					thinkingText: combinedThinkingText,
					text: combinedContent,
					image_url: combinedImageUrl,
					webAddress: webAddress ? JSON.parse(webAddress) : null,
					isUser: false,
					id: result.length + 1,
					sessionId: sessionId
				})

				i = j
			} else {
				result.push({
					...item,
					text: item.content,
					isUser: item.role === 'user',
					id: result.length + 1,
					sessionId: sessionId
				})
				i++
			}
		}

		return result
	}
	const processSession = (session, imgList, ancestorsList, idCounterRef) => {
		if (!session) return

		if (session.sketchIDAndUrl) {
			imgList.push(session.sketchIDAndUrl)
		}

		const list = processDialogue(session.dialogue, 0, imgList, session.id)
		list.forEach((el) => {
			el.id = idCounterRef.value++
		})

		ancestorsList.push(...list)
	}

	const setChatInfo = (info) => {
		const initialData = agentStore.getInitialProjectData
		if (isGenerating.value || initialData) return
		console.log('---', info)
		const data = info.conversation
		let project = info.project
		if (info.id) {
			project = info
		}

		params.versionID = ''
		sketchList.value = []
		params.useReport = false

		if (project) {
			params.configParams.type = project.type || ''
			params.configParams.region = project.region || project.area || ''
			params.configParams.style = project.style || ''
			params.configParams.temperature = project.temperature
			params.projectID = project.id
		}
		if (!data) {
			messageList.value = []
			return
		}
		const { ancestors, current } = data

		const imgList = []
		const ancestorsList = []
		const idCounterRef = { value: 1 }

		ancestors?.forEach((item) => {
			processSession(item, imgList, ancestorsList, idCounterRef)
		})

		processSession(current, imgList, ancestorsList, idCounterRef)

		nextTick(() => {
			ancestorsList.forEach((item) => {
				if (item.image_url && item.role !== 'user') {
					item.text += `<slot slot-name="sketch"></slot>`
				}
			})
			applyProjectParameterTags(ancestorsList, project)
			// console.log('ancestorslist', ancestorsList)
			messageList.value = [...ancestorsList]
			params.versionID = current?.id
			sketchList.value = imgList
		})
	}

	// 防止插入重复图片
	const mergeUniqueKeys = (targetArr, newData) => {
		const existingKeys = new Set(targetArr.flatMap((item) => Object.keys(item)))

		Object.entries(newData).forEach(([key, value]) => {
			if (!existingKeys.has(key)) {
				targetArr.push({ [key]: value })
				existingKeys.add(key)
			}
		})
	}

	defineExpose({
		setChatInfo,
		isGenerating
	})
</script>

<style lang="less" scoped>
	.c-svg {
		width: initial;
	}
	.agent-container {
		// width: 39%;
		// width: 63.4rem;
		// flex: 1;
		width: 67.4rem;
		margin-right: 2.7rem;
		background-color: #fff;
		border-radius: 2rem;
		box-shadow: 0px 15px 21px 0px #0000000d;

		.agent-header {
			height: 7.4rem;
			border-bottom: 0.1rem solid #c9c9c9;
			padding: 1.4rem 3.4rem 1.4rem 3.1rem;

			.agent-title {
				font-size: 1.8rem;
				margin-bottom: 0.6rem;
			}

			.agent-name {
				font-size: 1.4rem;
			}
		}
		.agent-body {
			padding: 3.2rem;
			overflow: hidden;
			row-gap: 2.4rem;
			.assist-input-wrapper {
				width: 100%;
				// height: 14.4rem;
				min-height: 14.4rem !important;
				max-height: 18.1rem !important;
			}
		}
		.input-wrapper {
			height: 14.4rem;
			padding: 0 2rem 3rem;
		}
	}
</style>
