import type { Ref } from 'vue'
import type { Emits, FlowHooks } from '~/types'

// flow event hooks
export const createHooks = (): FlowHooks => ({
  edgesChange: createEventHook(),
  nodesChange: createEventHook(),
  nodeDoubleClick: createEventHook(),
  nodeClick: createEventHook(),
  nodeMouseEnter: createEventHook(),
  nodeMouseMove: createEventHook(),
  nodeMouseLeave: createEventHook(),
  nodeContextMenu: createEventHook(),
  nodeDragStart: createEventHook(),
  nodeDrag: createEventHook(),
  nodeDragStop: createEventHook(),
  nodesInitialized: createEventHook(),
  miniMapNodeClick: createEventHook(),
  miniMapNodeDoubleClick: createEventHook(),
  miniMapNodeMouseEnter: createEventHook(),
  miniMapNodeMouseMove: createEventHook(),
  miniMapNodeMouseLeave: createEventHook(),
  connect: createEventHook(),
  connectStart: createEventHook(),
  connectEnd: createEventHook(),
  paneReady: createEventHook(),
  move: createEventHook(),
  moveStart: createEventHook(),
  moveEnd: createEventHook(),
  selectionDragStart: createEventHook(),
  selectionDrag: createEventHook(),
  selectionDragStop: createEventHook(),
  selectionContextMenu: createEventHook(),
  paneScroll: createEventHook(),
  paneClick: createEventHook(),
  paneContextMenu: createEventHook(),
  paneMouseEnter: createEventHook(),
  paneMouseMove: createEventHook(),
  paneMouseLeave: createEventHook(),
  edgeContextMenu: createEventHook(),
  edgeMouseEnter: createEventHook(),
  edgeMouseMove: createEventHook(),
  edgeMouseLeave: createEventHook(),
  edgeDoubleClick: createEventHook(),
  edgeClick: createEventHook(),
  edgeUpdateStart: createEventHook(),
  edgeUpdate: createEventHook(),
  edgeUpdateEnd: createEventHook(),
  updateNodeInternals: createEventHook(),
})

export function useHooks(emit: Emits, hooks: Ref<FlowHooks>) {
  onBeforeMount(() => {
    for (const [key, value] of Object.entries(hooks.value)) {
      const listener = (data: any) => {
        emit(key as Emits extends (event: infer Event) => void ? Event : never, data)
      }

      value.on(listener)

      tryOnScopeDispose(() => {
        value.off(listener)
      })
    }
  })
}
