<script setup lang="ts">
import { useLoading } from '/@/utils/loading-util'
import { computed, onMounted, ref, watch } from 'vue'
import DashboardDesigner from '/@/components/assistant/DashboardDesigner.vue'
import DashboardViewer from '/@/components/assistant/DashboardViewer.vue'
import ComponentLibrary from '/@/components/assistant/ComponentLibrary.vue'
import { ElMessage } from 'element-plus'
import type { MarkdownDashBoard, Position, Size, Content, AddCardData, ComponentLibraryItem } from '/@/components/assistant/types'
import { LmSession, Message } from '/@/api/assist/type'
import assist from '/@/api/assist'
import MarkdownIt from 'markdown-it'
import { PieChart, View } from '@element-plus/icons-vue'
import { useRoute } from 'vue-router'

const route = useRoute()

const id = computed(() => route.query.id as unknown as number)

const cards = ref<MarkdownDashBoard[]>([])
const title = ref<string>('新建仪表板')

// 预览相关状态
const showPreviewDialog = ref(false)

const { loading: loadingDashboard, doLoading: doLoadingDashBoard } = useLoading(async () => {
	if (id.value === undefined) {
		return
	}
	const res = await assist.dashboard.detail(id.value)
	title.value = res.title
	cards.value = JSON.parse(res.data)
})

const renderer = computed<MarkdownDashBoard[]>(() => [...cards.value].sort((a, b) => a.z - b.z))

// 生成唯一ID
const generateId = () => {
	return `card-${Date.now()}-${Math.random().toString(36).substring(2, 9)}`
}

const { loading: loadingDashboardSubmit, doLoading: doLoadingDashboardSubmit } = useLoading(async () => {
	try {
		assist.dashboard.edit({
			id: id.value,
			title: title.value,
			data: JSON.stringify(cards.value),
		})
		ElMessage.success('仪表板保存成功')
	} catch (error) {
		ElMessage.error('保存失败')
		throw error
	}
})

// 添加新卡片
const addCard = (cardData: AddCardData) => {
	const newCard: MarkdownDashBoard = {
		id: generateId(),
		x: cardData.x ?? Math.random() * 50, // 使用传入位置或随机位置
		y: cardData.y ?? Math.random() * 50,
		w: 30,
		h: 25,
		z: Math.max(...cards.value.map((item) => item.z), 0) + 1,
		type: cardData.type,
		title: cardData.title,
		data: cardData.data,
	}
	cards.value.push(newCard)
}

// 更新卡片位置
const updateCardPosition = (id: string, position: Position) => {
	const card = cards.value.find((item) => item.id === id)
	if (card) {
		card.x = position.x
		card.y = position.y
	}
}

// 更新卡片大小
const updateCardSize = (id: string, size: Size) => {
	const card = cards.value.find((item) => item.id === id)
	if (card) {
		card.w = size.w
		card.h = size.h
	}
}

// 更新卡片内容
const updateCardContent = (id: string, content: Content) => {
	const card = cards.value.find((item) => item.id === id)
	if (card) {
		card.title = content.title
		card.data = content.data
	}
}

// 删除卡片
const removeCard = (id: string) => {
	const index = cards.value.findIndex((item) => item.id === id)
	if (index !== -1) {
		cards.value.splice(index, 1)
	}
}

// 上移卡片层级
const moveCardUp = (id: string) => {
	const card = cards.value.find((item) => item.id === id)
	if (card) {
		// 找到当前卡片上方最近的卡片
		const upperCards = cards.value.filter((item) => item.z > card.z)
		if (upperCards.length > 0) {
			// 找到z值最小的上层卡片
			const nearestUpperCard = upperCards.reduce((min, current) =>
				current.z < min.z ? current : min
			)
			// 交换z值
			const tempZ = card.z
			card.z = nearestUpperCard.z
			nearestUpperCard.z = tempZ
		}
	}
}

// 下移卡片层级
const moveCardDown = (id: string) => {
	const card = cards.value.find((item) => item.id === id)
	if (card) {
		// 找到当前卡片下方最近的卡片
		const lowerCards = cards.value.filter((item) => item.z < card.z)
		if (lowerCards.length > 0) {
			// 找到z值最大的下层卡片
			const nearestLowerCard = lowerCards.reduce((max, current) =>
				current.z > max.z ? current : max
			)
			// 交换z值
			const tempZ = card.z
			card.z = nearestLowerCard.z
			nearestLowerCard.z = tempZ
		}
	}
}

const chat = ref<LmSession[]>([])
const currentSelectedChat = ref<number>()

watch(currentSelectedChat, (newVal) => {
	if (newVal === undefined) {
		//	/** 组件唯一标识 */
		// id: string
		// /** 组件标题 */
		// title: string
		// /** 组件图标 */
		// icon: any
		// /** 组件描述 */
		// description: string
		// /** 组件完整数据 */
		// data: string
		// /** 组件预览数据 */
		// preview: string
		library.value = defaultLibrary
		return
	}
	if (chat.value[newVal]?.session_id === undefined) {
		return
	}
	doLoadingLibrary(chat.value[newVal].session_id)
})

const { loading: loadingChat, doLoading: doLoadingChat } = useLoading(async () => {
	const data: { list: LmSession[]; total: number } = await assist.session
		.list({
			pageNum: 1,
			pageSize: 30,
		})
		.catch(() => {
			return {
				list: [],
				total: 0,
			}
		})

	chat.value = data.list
})

const defaultLibrary: ComponentLibraryItem[] = [
	{
		id: Math.random().toString(),
		icon: 'ele-PieChart',
		description: '测试',
		type: 'markdown',
		data: '测试',
		preview: '测试',
	},
]

// 组件库数据
const library = ref<ComponentLibraryItem[]>(defaultLibrary)

const { loading: loadingLibrary, doLoading: doLoadingLibrary } = useLoading(async (id: number) => {
	const result: {
		messages: Message[]
		total: number
	} = await assist.session.message.list({ sessionId: id }).catch(() => {
		return {
			list: [],
			total: 0,
		}
	})

	const messages = result.messages.filter((it) => it.role === 'assistant')

	// 解析消息内容，提取echarts和表格
	library.value = parseMessagesForLibrary(messages)
})

// 解析消息内容，提取echarts代码块和表格
const parseMessagesForLibrary = (messages: Message[]): ComponentLibraryItem[] => {
	const libraryItems: ComponentLibraryItem[] = []
	const md = new MarkdownIt({
		html: true,
		linkify: true,
		typographer: true,
	})

	messages.forEach((message, messageIndex) => {
		if (!message.render_content) return

		// 解析markdown内容为tokens
		const tokens = md.parse(message.render_content, {})

		// 提取echarts代码块
		extractEchartsFromTokens(tokens, messageIndex, libraryItems)

		// 提取表格
		extractTablesFromTokens(tokens, messageIndex, libraryItems)

		// 提取结构化数据
		extractStructDataFromTokens(tokens, messageIndex, libraryItems)
	})

	return libraryItems
}

// 验证JSON格式（echarts）
const isValidEchartsJSON = (str: string): boolean => {
	if (str.startsWith('[')) {
		return false
	}
	try {
		const expr = JSON.parse(str)
		return expr['series'] !== undefined
	} catch {
		return false
	}
}

// 从tokens中提取echarts代码块
const extractEchartsFromTokens = (tokens: any[], messageIndex: number, libraryItems: ComponentLibraryItem[]) => {
	tokens.forEach((token, tokenIndex) => {
		if (token.type === 'fence') {
			const info = token.info ? token.info.trim() : ''
			const content = token.content.trim()

			if ((info === 'echarts' || info === 'json') && isValidEchartsJSON(content)) {
				try {
					const config = JSON.parse(content)
					const title = config.title?.text || `图表 ${libraryItems.length + 1}`

					libraryItems.push({
						id: `echarts-${messageIndex}-${tokenIndex}`,
						title: title,
						icon: PieChart,
						description: `来自消息的ECharts图表`,
						type: 'echarts',
						data: content,
						preview: content,
					})
				} catch (error) {
					console.warn('解析echarts配置失败:', error)
				}
			}
		}
	})
}

// 从tokens中提取echarts代码块
const extractStructDataFromTokens = (tokens: any[], messageIndex: number, libraryItems: ComponentLibraryItem[]) => {
	tokens.forEach((token, tokenIndex) => {
		if (token.type === 'fence') {
			const info = token.info ? token.info.trim() : ''
			const content = token.content.trim()

			if (info === 'structdata') {
				try {
					libraryItems.push({
						id: `struct-${messageIndex}-${tokenIndex}`,
						icon: PieChart,
						description: `来自消息的动态图表`,
						type: 'structdata',
						data: content,
						preview: content,
					})
				} catch (error) {
					console.warn('解析struct配置失败:', error)
				}
			}
		}
	})
}


// 解析表格数据的接口
interface TableData {
	headers: string[]
	rows: string[][]
}

// 从tokens中提取表格
const extractTablesFromTokens = (tokens: any[], messageIndex: number, libraryItems: ComponentLibraryItem[]) => {
	tokens.forEach((token, tokenIndex) => {
		if (token.type === 'table_open') {
			const tableData = parseTableDataFromTokens(tokens, tokenIndex + 1)

			if (tableData.headers.length > 0 || tableData.rows.length > 0) {
				const title = `表格 ${libraryItems.length + 1}`
				const previewData = {
					headers: tableData.headers.slice(0, 3), // 只显示前3列
					rows: tableData.rows.slice(0, 3), // 只显示前3行
				}

				libraryItems.push({
					id: `table-${messageIndex}-${tokenIndex}`,
					title: title,
					icon: 'ele-Table',
					type: 'markdown',
					description: `来自消息的数据表格 (${tableData.rows.length}行 x ${tableData.headers.length}列)`,
					data: generateMarkdownTable(tableData),
					preview: generateMarkdownTable(previewData),
				})
			}
		}
	})
}

// 解析表格tokens获取数据
const parseTableDataFromTokens = (tokens: any[], startIdx: number): TableData => {
	const headers: string[] = []
	const rows: string[][] = []
	let currentRow: string[] = []
	let inHeader = false
	let inBody = false
	let cellContent = ''

	for (let i = startIdx; i < tokens.length; i++) {
		const token = tokens[i]

		if (token.type === 'table_close') {
			break
		}

		if (token.type === 'thead_open') {
			inHeader = true
			continue
		}

		if (token.type === 'thead_close') {
			inHeader = false
			continue
		}

		if (token.type === 'tbody_open') {
			inBody = true
			continue
		}

		if (token.type === 'tbody_close') {
			inBody = false
			continue
		}

		if (token.type === 'tr_open') {
			currentRow = []
			continue
		}

		if (token.type === 'tr_close') {
			if (inHeader && currentRow.length > 0) {
				headers.push(...currentRow)
			} else if (inBody && currentRow.length > 0) {
				rows.push([...currentRow])
			}
			currentRow = []
			continue
		}

		if (token.type === 'th_open' || token.type === 'td_open') {
			cellContent = ''
			continue
		}

		if (token.type === 'th_close' || token.type === 'td_close') {
			currentRow.push(cellContent.trim())
			cellContent = ''
			continue
		}

		if (token.type === 'inline' && token.children) {
			// 处理内联内容
			for (const child of token.children) {
				if (child.type === 'text') {
					cellContent += child.content
				} else if (child.type === 'code_inline') {
					cellContent += `\`${child.content}\``
				} else if (child.type === 'strong_open') {
					cellContent += '**'
				} else if (child.type === 'strong_close') {
					cellContent += '**'
				} else if (child.type === 'em_open') {
					cellContent += '*'
				} else if (child.type === 'em_close') {
					cellContent += '*'
				}
			}
		}
	}

	return { headers, rows }
}

// 生成markdown表格
const generateMarkdownTable = (tableData: TableData): string => {
	if (tableData.headers.length === 0 && tableData.rows.length === 0) {
		return ''
	}

	let markdown = ''

	// 生成表头
	if (tableData.headers.length > 0) {
		markdown += '| ' + tableData.headers.join(' | ') + ' |\n'
		markdown += '| ' + tableData.headers.map(() => '---').join(' | ') + ' |\n'
	}

	// 生成表格行
	tableData.rows.forEach((row) => {
		markdown += '| ' + row.join(' | ') + ' |\n'
	})

	return markdown
}

// 打开预览对话框
const openPreview = () => {
	showPreviewDialog.value = true
}

// 关闭预览对话框
const closePreview = () => {
	showPreviewDialog.value = false
}

onMounted( () => {
	doLoadingChat()
	doLoadingDashBoard()
})
</script>

<template>
	<div class="dashboard-edit-container">
		<!-- 顶部工具栏 -->
		<div class="toolbar">
			<div class="toolbar-left">
				<h2>仪表板设计器 | {{ title }}</h2>
			</div>
			<div class="toolbar-right">
				<el-button :icon="View" @click="openPreview" :disabled="loadingDashboard">
					预览
				</el-button>
				<el-button type="primary" @click="doLoadingDashboardSubmit" :loading="loadingDashboardSubmit" :disabled="loadingDashboard">
					保存仪表板
				</el-button>
			</div>
		</div>

		<!-- 主要内容区域 -->
		<div class="main-content" v-loading="loadingDashboard">
			<!-- 左侧设计器面板 -->
			<div class="designer-panel">
				<DashboardDesigner
					:cards="renderer"
					@update-position="updateCardPosition"
					@update-size="updateCardSize"
					@update-content="updateCardContent"
					@remove-card="removeCard"
					@add-card="addCard"
					@move-card-up="moveCardUp"
					@move-card-down="moveCardDown"
				/>
			</div>

			<!-- 右侧组件库面板 -->
			<div class="library-panel">
				<el-select class="library-panel-header" v-model="currentSelectedChat" v-loading="loadingChat" clearable @clear="currentSelectedChat = undefined">
					<el-option v-for="(i, index) in chat" :key="i.session_id" :value="index" :label="i.title"></el-option>
				</el-select>
				<ComponentLibrary class="library-panel-content" v-loading="loadingLibrary" :library="library" @add-card="addCard" />
			</div>
		</div>

		<!-- 预览对话框 -->
		<el-dialog
			v-model="showPreviewDialog"
			title="仪表板预览"
			width="90%"
			:before-close="closePreview"
			append-to-body
			class="preview-dialog"
		>
			<div class="preview-container">
				<DashboardViewer :cards="renderer" />
			</div>
		</el-dialog>
	</div>
</template>

<style scoped lang="scss">
.dashboard-edit-container {
	height: 100vh;
	display: flex;
	flex-direction: column;
	background: var(--el-bg-color-page);
}

.toolbar {
	display: flex;
	justify-content: space-between;
	align-items: center;
	padding: 16px 24px;
	background: var(--el-bg-color);
	border-bottom: 1px solid var(--el-border-color-light);
	box-shadow: 0 1px 4px rgba(0, 0, 0, 0.1);

	.toolbar-left {
		h2 {
			margin: 0;
			color: var(--el-text-color-primary);
			font-size: 18px;
			font-weight: 600;
		}
	}

	.toolbar-right {
		display: flex;
		gap: 12px;
	}
}

.main-content {
	flex: 1;
	display: flex;
	overflow: hidden;
}

.designer-panel {
	flex: 1;
	background: var(--el-bg-color);
	border-right: 1px solid var(--el-border-color-light);
}

.library-panel {
	width: 300px;
	background: var(--el-bg-color);
	border-left: 1px solid var(--el-border-color-light);

	display: flex;
	flex-direction: column;
	align-items: center;

	.library-panel-header {
		width: 95%;
		margin: 5%;
	}

	.library-panel-content {
		width: 100%;
	}
}

/* 预览对话框样式 */
:deep(.preview-dialog) {
	.el-dialog__body {
		padding: 0;
		height: 70vh;
	}
}

.preview-container {
	height: 100%;
	border: 1px solid var(--el-border-color-light);
	border-radius: 6px;
	overflow: hidden;
}
</style>
