<script lang="ts" setup>
import type { CanvasConnection, CanvasElement } from '@/types';
import type { NodeDragEvent, Connection } from '@vue-flow/core';
import { VueFlow, PanelPosition } from '@vue-flow/core';
import { Background } from '@vue-flow/background';
import { Controls } from '@vue-flow/controls';
import { MiniMap } from '@vue-flow/minimap';
import CanvasNode from './elements/nodes/CanvasNode.vue';
import CanvasEdge from './elements/edges/CanvasEdge.vue';
import { useCssModule } from 'vue';

const $style = useCssModule();

const emit = defineEmits<{
	'update:modelValue': [elements: CanvasElement[]];
	'update:node:position': [id: string, position: { x: number; y: number }];
	'create:connection': [connection: Connection];
}>();

withDefaults(
	defineProps<{
		id?: string;
		elements: CanvasElement[];
		connections: CanvasConnection[];
		controlsPosition?: PanelPosition;
	}>(),
	{
		id: 'canvas',
		elements: () => [],
		connections: () => [],
		controlsPosition: PanelPosition.BottomLeft,
	},
);

function onNodeDragStop(e: NodeDragEvent) {
	e.nodes.forEach((node) => {
		emit('update:node:position', node.id, node.position);
	});
}

function onConnect(...args: unknown[]) {
	emit('create:connection', args[0] as Connection);
}
</script>

<template>
	<VueFlow
		:id="id"
		:nodes="elements"
		:edges="connections"
		:apply-changes="false"
		fit-view-on-init
		pan-on-scroll
		:min-zoom="0.2"
		:max-zoom="2"
		data-test-id="canvas"
		@node-drag-stop="onNodeDragStop"
		@connect="onConnect"
	>
		<template #node-canvas-node="canvasNodeProps">
			<CanvasNode v-bind="canvasNodeProps" />
		</template>

		<template #edge-canvas-edge="canvasEdgeProps">
			<CanvasEdge v-bind="canvasEdgeProps" />
		</template>

		<Background data-test-id="canvas-background" pattern-color="#aaa" :gap="16" />

		<MiniMap data-test-id="canvas-minimap" pannable />

		<Controls
			data-test-id="canvas-controls"
			:class="$style.canvasControls"
			:position="controlsPosition"
		></Controls>
	</VueFlow>
</template>

<style lang="scss" module></style>

<style lang="scss">
.vue-flow__controls {
	display: flex;
	gap: var(--spacing-2xs);
	box-shadow: none;
}

.vue-flow__controls-button {
	width: 42px;
	height: 42px;
	border: var(--border-base);
	border-radius: var(--border-radius-base);
	padding: 0;
	transition-property: transform, background, border, color;
	transition-duration: 300ms;
	transition-timing-function: ease;

	&:hover {
		border-color: var(--color-button-secondary-hover-active-border);
		background-color: var(--color-button-secondary-active-background);
		transform: scale(1.1);

		svg {
			fill: var(--color-primary);
		}
	}

	svg {
		max-height: 16px;
		max-width: 16px;
		transition-property: fill;
		transition-duration: 300ms;
		transition-timing-function: ease;
	}
}
</style>
