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

import type { CanvasElementPortWithRenderData, IWorkflowNode } from '../Interface'

export interface CanvasNodeContext {
	props: ComputedRef<
		NodeProps<IWorkflowNode> & {
			readOnly?: boolean
			hovered?: boolean
			node: IWorkflowNode
			data: IWorkflowNode['data']
		}
	>
	inputs: ComputedRef<CanvasElementPortWithRenderData[]>
	outputs: ComputedRef<CanvasElementPortWithRenderData[]>
}

const canvasNodeContextKey: InjectionKey<CanvasNodeContext> = Symbol('canvas-node-context')

export function provideCanvasNodeContext(options: {
	props: MaybeRefOrGetter<
		NodeProps<IWorkflowNode> & {
			readOnly?: boolean
			hovered?: boolean
			node: IWorkflowNode
			data: IWorkflowNode['data']
		}
	>
	inputs: MaybeRefOrGetter<CanvasElementPortWithRenderData[]>
	outputs: MaybeRefOrGetter<CanvasElementPortWithRenderData[]>
}): CanvasNodeContext {
	const context: CanvasNodeContext = {
		props: computed(() => unref(options.props)),
		inputs: computed(() => unref(options.inputs)),
		outputs: computed(() => unref(options.outputs))
	}

	provide(canvasNodeContextKey, context)

	return context
}

export function useCanvasNodeContext(): CanvasNodeContext {
	const context = inject(canvasNodeContextKey, null)

	if (!context) {
		throw new Error('useCanvasNodeContext must be used within CanvasNode')
	}

	return context
}
