<template>
	<div class="w-full h-full flex flex-col">
		<div
			class="h-60px shrink-0 border-b border-b-solid border-gray-200 flex items-center justify-between px-12px"
		>
			<div class="left flex items-center gap-4">
				<el-breadcrumb separator="/" class="flex items-center">
					<el-breadcrumb-item>{{ t('pages.editor.workspace') }}</el-breadcrumb-item>
					<el-breadcrumb-item>
						<Input ref="inputRef" v-model="workflow.name" variant="borderless" />
					</el-breadcrumb-item>
				</el-breadcrumb>

				<div class="flex gap-2" v-show="!showTagInput" @click="showTagInput = true">
					<el-tag type="info" v-for="tag in workflow.tags" :key="tag" :disable-transitions="false">
						{{ tag }}
					</el-tag>
				</div>

				<el-input-tag
					v-show="showTagInput"
					v-model="workflow.tags"
					:placeholder="t('pages.editor.tagPlaceholder')"
					:aria-label="t('pages.editor.tagPlaceholder')"
					:max="5"
					@blur="showTagInput = false"
				/>

				<IconButton
					v-if="!workflow.tags?.length && !showTagInput"
					icon="iconoir:plus"
					type="primary"
					link
					@click="showTagInput = true"
				>
					{{ t('pages.editor.tagButton') }}
				</IconButton>
			</div>

			<div class="right flex items-center gap-2">
				<PublishBtn :workflow="workflow" @published="handlePublished" />
				<IconButton icon="lucide:history" type="default" link></IconButton>
				<el-dropdown placement="bottom-end" popper-class="w-120px">
					<IconButton icon="fluent-mdl2:more" type="default" link></IconButton>
					<template #dropdown>
						<el-dropdown-item>{{ t('pages.editor.menu.description') }}</el-dropdown-item>
						<el-dropdown-item>{{ t('pages.editor.menu.reuse') }}</el-dropdown-item>
						<el-dropdown-item @click="handleRename">{{
							t('pages.editor.menu.rename')
						}}</el-dropdown-item>
						<el-dropdown-item divided @click="handleDelete">{{
							t('pages.editor.menu.delete')
						}}</el-dropdown-item>
					</template>
				</el-dropdown>
			</div>
		</div>

		<el-splitter layout="vertical" class="flex-1">
			<el-splitter-panel>
				<NodeView :key="workflow.id" :workflow="workflow" :reload-workflow="loadAgentWorkflow" />
			</el-splitter-panel>

			<el-splitter-panel v-model:size.lazy="footerHeight" :min="32">
				<EditorFooter @toggle="handleFooterToggle" />
			</el-splitter-panel>
		</el-splitter>
	</div>
</template>

<script setup lang="ts">
import { inject, nextTick, onBeforeUnmount, ref, type CSSProperties, watch } from 'vue'
import { useRoute, useRouter } from 'vue-router'
import { dayjs, ElMessage, ElMessageBox } from 'element-plus'
import { agent } from '@repo/api-service'

import EditorFooter from '@/features/editorFooter/index.vue'
import NodeView from './NodeView.vue'
import PublishBtn from './PublishBtn.vue'
import { nodeMap } from '@/nodes'
import { IconButton, Input } from '@repo/ui'
import { useI18n } from '@/composables/useI18n'

import type { IWorkflow } from '@repo/workflow'

const layout = inject<{ setMainStyle: (style: CSSProperties) => void }>('layout')

layout?.setMainStyle({
	padding: '0px'
})

const route = useRoute()
const router = useRouter()
const { t } = useI18n()
const footerHeight = ref(32)
const showTagInput = ref(false)
const inputRef = ref<InstanceType<typeof Input>>()
const saveAgentTimer = ref<number | undefined>(undefined)
const saveVarsTimer = ref<number | undefined>(undefined)
const isHydrating = ref(false)
const notifyTimestamps = new Map<string, number>()

const id = route.params?.id as string
const projectMap = JSON.parse(localStorage.getItem('workflow-map') || '{}') as Record<
	string,
	IWorkflow
>

const workflow = ref<IWorkflow>(
	projectMap?.[id]
		? projectMap[id]
		: {
				id,
				name: 'workflow_1',
				created: dayjs().format('MM 月DD 日'),
				nodes: [],
				edges: []
			}
)

// 从后端节点数据中提取当前画布需要的节点类型。
const normalizeNodeType = (node: any) => {
	const sourceNodeType = node?.nodeType || node?.data?.nodeType || node?.data?.type || node?.type
	return sourceNodeType || 'code'
}

// 将原始节点数据转换为画布组件可直接消费的节点结构。
const toWorkflowNode = (node: any) => {
	const normalizedNodeType = normalizeNodeType(node)
	const schema = nodeMap[normalizedNodeType]?.schema
	const position = node?.position || schema?.position || { x: 20, y: 30 }
	const width = node?.width ?? schema?.width ?? 96
	const height = node?.height ?? schema?.height ?? 96

	return {
		...schema,
		...node,
		id: node.id,
		type: 'canvas-node',
		position,
		width,
		height,
		zIndex: node?.zIndex ?? schema?.zIndex ?? 1,
		selected: false,
		data: {
			...(schema?.data || {}),
			...(node?.data || {}),
			id: node.id,
			position,
			width,
			height,
			nodeType: normalizedNodeType
		}
	}
}

// 将跨循环作用域的边重定向到父节点，确保外层画布能正确渲染。
const normalizeEdgeEndpoints = (
	edge: { source: string; target: string },
	nodes: Array<{ id: string; parentId?: string }>
) => {
	const sourceNode = nodes.find((node) => node.id === edge.source)
	const targetNode = nodes.find((node) => node.id === edge.target)

	const sourceParentId = sourceNode?.parentId || ''
	const targetParentId = targetNode?.parentId || ''

	if (sourceParentId && sourceParentId !== targetParentId) {
		return {
			source: sourceParentId,
			target: edge.target
		}
	}

	if (targetParentId && targetParentId !== sourceParentId) {
		return {
			source: edge.source,
			target: targetParentId
		}
	}

	return edge
}

// 为边补齐兜底 id 和 handle，避免画布渲染时缺少必要字段。
const toWorkflowEdge = (
	edge: any,
	index: number,
	nodes: Array<{ id: string; parentId?: string }> = []
) => {
	if (!edge || typeof edge !== 'object' || !edge.source || !edge.target) {
		return null
	}

	const normalizedEdge = normalizeEdgeEndpoints(edge, nodes)

	return {
		...edge,
		...normalizedEdge,
		sourceHandle: edge.sourceHandle === 'source' ? `${edge.source}-source` : edge.sourceHandle,
		targetHandle: edge.targetHandle === 'target' ? `${edge.target}-target` : edge.targetHandle,
		id: edge.id || `edge-${normalizedEdge.source}-${normalizedEdge.target}-${index}`,
		type: 'canvas-edge',
		data: edge.data || {}
	}
}

// 自动保存频繁触发时，避免重复弹出相同成功提示。
const notifySuccess = (key: string, message: string, cooldown = 1500) => {
	const now = Date.now()
	const last = notifyTimestamps.get(key) || 0
	if (now - last < cooldown) return

	notifyTimestamps.set(key, now)
	ElMessage.success(message)
}

// 统一处理编辑页保存类接口的成功与失败提示。
const handleApiResult = (response: any, successMessage?: string, errorMessage?: string) => {
	if (response?.isSuccess) {
		if (successMessage) {
			notifySuccess(successMessage, successMessage)
		}
		return true
	}
	if (response?.code === 0 && response?.error) {
		ElMessage.error(response.error)
		return false
	}
	if (errorMessage) {
		ElMessage.error(errorMessage)
	}
	return false
}

// 画布依赖归一化后的节点和边结构，因此在页面入口统一完成数据适配。
const loadAgentWorkflow = async (agentId: string) => {
	if (!agentId) return
	isHydrating.value = true

	try {
		const response = await agent.postAgentGetAgentInfo({ id: agentId })
		const result = response?.result
		if (!response?.isSuccess || !result) {
			throw new Error('获取智能体信息失败')
		}

		const normalizedNodes = (result.nodes || []).map(toWorkflowNode)
		const normalizedEdges = (result.edges || [])
			.map((edge: any, index: number) => toWorkflowEdge(edge, index, normalizedNodes))
			.filter(Boolean)

		workflow.value = {
			...(result as unknown as IWorkflow),
			nodes: normalizedNodes,
			edges: normalizedEdges as IWorkflow['edges']
		}
		await nextTick()
	} catch (error) {
		console.error('loadAgentWorkflow error', error)
		ElMessage.error(t('pages.editor.messages.loadFailed'))
	} finally {
		isHydrating.value = false
	}
}

// 保存页面头部编辑的工作流基础信息。
const saveAgentMeta = async () => {
	if (!workflow.value?.id) return

	try {
		const response = await agent.postAgentDoEditAgent({
			data: workflow.value
		})
		handleApiResult(
			response,
			t('pages.editor.messages.saved'),
			t('pages.editor.messages.saveFailed')
		)
	} catch (error) {
		console.error('saveAgentMeta error', error)
		ElMessage.error(t('pages.editor.messages.saveFailed'))
	}
}

// 保存不在节点画布内编辑的工作流变量。
const saveAgentVariables = async () => {
	if (!workflow.value?.id) return

	try {
		const response = await agent.postAgentDoSaveAgentVariables({
			appAgentId: workflow.value.id,
			conversation_variables: workflow.value.conversation_variables || [],
			env_variables: (workflow.value.env_variables || []).map((item: any) => ({
				name: item?.name || '',
				value: item?.value ?? '',
				type: item?.type || 'string'
			}))
		})
		handleApiResult(
			response,
			t('pages.editor.messages.varsSaved'),
			t('pages.editor.messages.saveFailed')
		)
	} catch (error) {
		console.error('saveAgentVariables error', error)
		ElMessage.error(t('pages.editor.messages.saveFailed'))
	}
}

// 为基础信息保存增加防抖，减少输入过程中的重复请求。
const scheduleSaveAgentMeta = () => {
	if (saveAgentTimer.value) window.clearTimeout(saveAgentTimer.value)
	if (!workflow.value?.id) return

	saveAgentTimer.value = window.setTimeout(() => {
		saveAgentMeta()
	}, 600)
}

// 为变量保存增加防抖，避免短时间内连续提交。
const scheduleSaveAgentVariables = () => {
	if (saveVarsTimer.value) window.clearTimeout(saveVarsTimer.value)
	if (!workflow.value?.id) return

	saveVarsTimer.value = window.setTimeout(() => {
		saveAgentVariables()
	}, 600)
}

watch(
	() => workflow.value,
	(currentWorkflow) => {
		projectMap[currentWorkflow.id] = currentWorkflow
		localStorage.setItem('workflow-map', JSON.stringify(projectMap))
	},
	{ deep: true }
)

watch(
	() => [workflow.value?.name, workflow.value?.description, workflow.value?.tags],
	() => {
		if (isHydrating.value) return
		scheduleSaveAgentMeta()
	},
	{ deep: true }
)

watch(
	() => [workflow.value?.conversation_variables, workflow.value?.env_variables],
	() => {
		if (isHydrating.value) return
		scheduleSaveAgentVariables()
	},
	{ deep: true }
)

watch(
	() => route.params?.id,
	async (nextId) => {
		if (nextId) {
			await loadAgentWorkflow(nextId as string)
		}
	},
	{ immediate: true }
)

// 根据底部面板开关状态调整面板高度。
const handleFooterToggle = (open: boolean) => {
	footerHeight.value = open ? 200 : 32
}

// 聚焦标题输入框，方便直接重命名当前工作流。
const handleRename = () => {
	inputRef.value?.focus()
	inputRef.value?.select()
}

// 删除本地缓存中的当前工作流并退出编辑页。
const handleDelete = () => {
	ElMessageBox.confirm(t('common.confirmDelete.message'), t('common.confirmDelete.title'), {
		confirmButtonText: t('common.confirm'),
		cancelButtonText: t('common.cancel'),
		type: 'warning'
	}).then(() => {
		localStorage.removeItem(`project_${id}`)
		router.push('/')
	})
}

const handlePublished = async () => {
	if (!workflow.value?.id) return
	await loadAgentWorkflow(workflow.value.id)
}

onBeforeUnmount(() => {
	if (saveAgentTimer.value) window.clearTimeout(saveAgentTimer.value)
	if (saveVarsTimer.value) window.clearTimeout(saveVarsTimer.value)
	layout?.setMainStyle({})
})
</script>
