import {
	computed,
	inject,
	provide,
	unref,
	type ComputedRef,
	type InjectionKey,
	type MaybeRefOrGetter,
	type Ref
} from 'vue'
import type { VueFlowStore } from '@vue-flow/core'

import type { IWorkflowEdge, IWorkflowNode, ConnectStartEvent } from '../Interface'

export interface VueFlowContext {
	id: ComputedRef<string>
	nodes: ComputedRef<IWorkflowNode[]>
	edges: ComputedRef<IWorkflowEdge[]>
	vueFlow: VueFlowStore
	nodeMap: ComputedRef<Record<string, any>>
	connectingHandle: Ref<ConnectStartEvent | undefined>
}

const vueFlowContextKey: InjectionKey<VueFlowContext> = Symbol('vueflow-context')

export function provideVueFlowContext(options: {
	id: MaybeRefOrGetter<string | undefined>
	nodes: MaybeRefOrGetter<IWorkflowNode[] | undefined>
	edges: MaybeRefOrGetter<IWorkflowEdge[] | undefined>
	vueFlow: VueFlowStore
	nodeMap: MaybeRefOrGetter<Record<string, any> | undefined>
	connectingHandle: Ref<ConnectStartEvent | undefined>
}): VueFlowContext {
	const context: VueFlowContext = {
		id: computed(() => unref(options.id) || 'canvas'),
		nodes: computed(() => unref(options.nodes) || []),
		edges: computed(() => unref(options.edges) || []),
		vueFlow: options.vueFlow,
		nodeMap: computed(() => unref(options.nodeMap) || {}),
		connectingHandle: options.connectingHandle
	}

	provide(vueFlowContextKey, context)

	return context
}

export function useVueFlowContext(): VueFlowContext {
	const context = inject(vueFlowContextKey, null)

	if (!context) {
		throw new Error('useVueFlowContext must be used within Canvas')
	}

	return context
}
