<template>
	<div class="cl-flow" id="cl-flow">
		<vue-flow
			:default-viewport="{ zoom: 1.0 }"
			:min-zoom="0.25"
			:max-zoom="2"
			@connect="onConnect"
			@node-mouse-enter="onNodeMouseEnter"
			@node-mouse-leave="onNodeMouseLeave"
			@node-click="onNodeClick"
			@node-drag-stop="onNodeDragStop"
			@node-context-menu="refs.contextMenu?.onNode"
			@edge-mouse-enter="onEdgeMouseEnter"
			@edge-mouse-leave="onEdgeMouseLeave"
			@pane-context-menu="refs.contextMenu?.onPane"
			@pane-click="onPaneClick"
			@pane-scroll="onPaneScroll"
			@pane-ready="onPaneReady"
		>
			<!-- 自定义顶部栏 -->
			<tools-head />

			<!-- 自定义选择框 -->
			<tools-selection />

			<!-- 自定义面板 -->
			<tools-panel />

			<!-- 自定义节点添加面板 -->
			<tools-node-add />

			<!-- 自定义右键菜单 -->
			<tools-context-menu :ref="setRefs('contextMenu')" />

			<!-- 自定义控制器 -->
			<tools-controls />

			<!-- 自定义连接线按钮 -->
			<template
				#edge-button="{
					id,
					sourceX,
					sourceY,
					targetX,
					targetY,
					sourcePosition,
					targetPosition,
					markerEnd,
					style,
					data
				}"
			>
				<tools-edge-button
					:id="id"
					:source-x="sourceX"
					:source-y="sourceY"
					:target-x="targetX"
					:target-y="targetY"
					:source-position="sourcePosition"
					:target-position="targetPosition"
					:marker-end="markerEnd"
					:style="style"
					:data="data"
				/>
			</template>

			<!-- 自定义节点 -->
			<template #[item.name!]="{ id }" v-for="item in flow.CustomNodes" :key="item.name">
				<tools-card :node-id="id" />
			</template>

			<!-- 背景 -->
			<background pattern-color="#aaa" :gap="16" />

			<!-- 小图 -->
			<mini-map position="bottom-right" :height="100" :width="150" />
		</vue-flow>
	</div>
</template>

<script setup lang="ts">
import {
	VueFlow,
	Connection,
	NodeDragEvent,
	EdgeMouseEvent,
	type NodeMouseEvent,
	type VueFlowStore
} from "@vue-flow/core";
import { Background } from "@vue-flow/background";
import { MiniMap } from "@vue-flow/minimap";
import { useFlow } from "../hooks";
import { useCool } from "/@/cool";
import "@vue-flow/core/dist/style.css";
import "@vue-flow/core/dist/theme-default.css";
import "@vue-flow/controls/dist/style.css";
import "@vue-flow/minimap/dist/style.css";
import "@vue-flow/node-resizer/dist/style.css";
import ToolsPanel from "./tools/panel/index.vue";
import ToolsCard from "./tools/card.vue";
import ToolsEdgeButton from "./tools/edge-button.vue";
import ToolsControls from "./tools/controls.vue";
import ToolsHead from "./tools/head.vue";
import ToolsContextMenu from "./tools/context-menu.vue";
import ToolsSelection from "./tools/selection.vue";
import ToolsNodeAdd from "./tools/node-add.vue";
import { ElMessage, ElMessageBox } from "element-plus";
import { onBeforeRouteLeave } from "vue-router";
import { onMounted, onUnmounted } from "vue";
import type { FlowNode } from "../types";
import { nextTick } from "vue";

const props = defineProps({
	flowId: Number
});

const { mitt, refs, setRefs } = useCool();
const flow = useFlow();

// 加载完
function onPaneReady(store: VueFlowStore) {
	flow.init();
	flow.get(props.flowId!);
}

// 滚轮滚动
function onPaneScroll(e: WheelEvent | undefined) {
	refs.contextMenu?.close();
}

// 线连接
function onConnect(connection: Connection) {
	flow.addEdge(connection);
}

// 节点点击
async function onNodeClick(e: NodeMouseEvent) {
	// 如果节点相同则不执行事件
	if (flow.node?.id == e.node.id) return false;

	const node = flow.findNode(e.node.id);

	flow.setNode(node);

	// 视图定位
	// flow.setViewportByNode(flow.node!);

	refs.contextMenu?.close();
}

// 节点鼠标移入
function onNodeMouseEnter(e: NodeMouseEvent) {
	flow.activeEdge(e.node.id, true);
}

// 节点鼠标移入
function onNodeMouseLeave(e: NodeMouseEvent) {
	flow.activeEdge(e.node.id, false);
}

// 节点拖拽结束
function onNodeDragStop(e: NodeDragEvent) {
	flow.updateNode(e.node.id, {
		position: e.node.position
	});
}

// 鼠标移入线
function onEdgeMouseEnter(e: EdgeMouseEvent) {
	e.edge.data.show = true;
}

// 鼠标移出线
function onEdgeMouseLeave(e: EdgeMouseEvent) {
	e.edge.data.show = false;
}

// 空白处点击
function onPaneClick() {
	refs.contextMenu?.close();
	flow.enableDrag();
	flow.clearNode();
}

// 打开表单
function openForm(node: FlowNode) {
	closeForm();

	if (node) {
		flow.updateChildrenPosition("open", node);

		setTimeout(() => {
			mitt.emit("flow.openForm", node);
		}, 100);
	}
}

// 关闭表单
function closeForm() {
	flow.updateChildrenPosition("close", flow.node!);
	mitt.emit("flow.closeForm", flow.node);
}

// 保存
async function save() {
	await flow.save();
	ElMessage.success("数据保存成功");
}

onMounted(() => {
	mitt.on("flow.setNode", openForm);
	mitt.on("flow.clearNode", closeForm);
	window.addEventListener("beforeunload", save);
});

onUnmounted(() => {
	mitt.off("flow.setNode", openForm);
	mitt.off("flow.clearNode", closeForm);
	window.removeEventListener("beforeunload", save);
});

let lock = false;

onBeforeRouteLeave((to, from, next) => {
	if (lock) {
		return next();
	}

	lock = true;

	ElMessageBox.confirm("退出前是否保存当前数据？", "提示", {
		type: "warning",
		confirmButtonText: "保存",
		cancelButtonText: "不保存",
		distinguishCancelAndClose: true,
		beforeClose(action, instance, done) {
			done();

			if (action == "confirm") {
				save();
				next();
			} else if (action == "cancel") {
				next();
			} else {
				lock = false;
				next(false);
			}
		}
	}).catch(() => null);
});
</script>

<style lang="scss">
.cl-flow {
	height: 100%;

	.vue-flow {
		height: 100%;
	}

	.vue-flow__minimap {
		margin: 0;
		bottom: 50px;
		right: 10px;
		height: 100px;
		border-radius: 6px;
		overflow: hidden;
		box-shadow: 0px 0 6px 1px rgba(16, 24, 40, 0.08);
	}

	.vue-flow__node:has(.is-moving) {
		transition: transform 0.1s;
	}
}
</style>
