<script setup lang="ts">
import { ref, watch, computed } from 'vue'
import {
	BaseEdge,
	EdgeLabelRenderer,
	getBezierPath,
	type EdgeProps,
	type Connection
} from '@vue-flow/core'
import { IconButton } from '@repo/ui'
import type { CanvasExecutionStatus } from '../../../Interface'
import { getExecutionStatusColor } from '../../../utils/execution-status'

defineOptions({
	inheritAttrs: false
})

const emit = defineEmits<{
	delete: [connection: Connection]
	add: [connection: Connection]
}>()

type CanvasEdgeProps = EdgeProps & {
	readOnly?: boolean
	hovered?: boolean
	bringToFront?: boolean // Determines if entire edges layer should be brought to front
}

const props = defineProps<CanvasEdgeProps>()
const path = computed(() => getBezierPath(props))
const executionStatus = computed<CanvasExecutionStatus>(
	() => (props.data?.executionStatus as CanvasExecutionStatus) || 'idle'
)
const isPendingEdge = computed(() => !!props.data?.pending)
const edgeStyle = computed(() => {
	const status = executionStatus.value
	const color = getExecutionStatusColor(status)

	return {
		stroke: isPendingEdge.value ? '#409EFF' : color,
		strokeWidth: 1.6,
		opacity: isPendingEdge.value ? 0.7 : 1,
		filter: status === 'idle' ? 'none' : `drop-shadow(0 0 8px ${color}55)`,
		transition: 'stroke 180ms ease, stroke-width 180ms ease, filter 180ms ease, opacity 180ms ease'
	}
})

const delayedHovered = ref(props.hovered)
const delayedHoveredSetTimeoutRef = ref<ReturnType<typeof setTimeout> | null>(null)
const delayedHoveredTimeout = 600

const connection = computed<Connection>(() => ({
	source: props.source,
	target: props.target,
	sourceHandle: props.sourceHandleId,
	targetHandle: props.targetHandleId,
	id: props.id
}))

watch(
	() => props.hovered,
	(isHovered) => {
		if (isHovered) {
			if (delayedHoveredSetTimeoutRef.value) clearTimeout(delayedHoveredSetTimeoutRef.value)
			delayedHovered.value = true
		} else {
			delayedHoveredSetTimeoutRef.value = setTimeout(() => {
				delayedHovered.value = false
			}, delayedHoveredTimeout)
		}
	},
	{ immediate: true }
)

const renderToolbar = computed(() => delayedHovered.value && !props.readOnly)

const onAdd = () => {
	emit('add', connection.value)
}

const onDelete = () => {
	emit('delete', connection.value)
}
</script>

<template>
	<BaseEdge
		:path="path[0]"
		:interaction-width="40"
		:marker-end="markerEnd"
		:style="edgeStyle"
		:class="['canvas-edge-path', { 'is-pending': isPendingEdge }]"
	/>

	<EdgeLabelRenderer>
		<div
			:style="{
				pointerEvents: 'all',
				position: 'absolute',
				transform: `translate(-50%, -50%) translate(${path[1]}px,${path[2]}px)`
			}"
			class="nodrag nopan"
		>
			<div v-if="isPendingEdge" class="text-sm text-gray-500">pendding...</div>
			<div v-if="renderToolbar && !isPendingEdge" class="flex">
				<IconButton :edge-add-btn="id" icon="lucide:plus" size="small" square @click="onAdd" />
				<IconButton icon="lucide:brush-cleaning" size="small" square @click="onDelete" />
			</div>
		</div>
	</EdgeLabelRenderer>
</template>

<style>
@keyframes edge-loading-dash {
	from {
		stroke-dashoffset: 0;
	}
	to {
		stroke-dashoffset: -28;
	}
}

.canvas-edge-path.is-pending {
	stroke-dasharray: 8 6;
	animation: edge-loading-dash 3.6s linear infinite;
}
</style>
