<script setup lang="ts">
import { $createVarLabelNode, $isVarLabelNode, VarLabelNode } from './VarLabel'
import { $createTextNode, $nodesOfType, type LexicalNode, TextNode } from 'lexical'
import { onMounted, onUnmounted } from 'vue'
import { useLexicalComposer } from 'lexical-vue'
import { splitTextByVariableSegments } from '../utils'

function varLabelTransform(node: TextNode) {
	if ($isVarLabelNode(node)) return

	const textContent = node.getTextContent()
	const segments = splitTextByVariableSegments(textContent)
	const hasVariable = segments.some((segment) => segment.kind === 'variable')
	if (!hasVariable) return

	const nodes = segments
		.map((segment) => {
			if (segment.kind === 'variable') {
				return $createVarLabelNode(`${segment.varType}-label`, segment.text)
			}
			if (!segment.text.length) return null
			return $createTextNode(segment.text)
		})
		.filter((segmentNode): segmentNode is LexicalNode => segmentNode !== null)

	if (!nodes.length) return

	const [firstNode, ...restNodes] = nodes
	if (!firstNode) return

	node.replace(firstNode)
	let currentNode: LexicalNode = firstNode
	for (const segmentNode of restNodes) {
		currentNode.insertAfter(segmentNode)
		currentNode = segmentNode
	}
}

const editor = useLexicalComposer()

onMounted(() => {
	const removeTransform = editor.registerNodeTransform(TextNode, varLabelTransform)
	const refreshVarLabelDecorators = () => {
		editor.update(() => {
			const varLabelNodes = $nodesOfType(VarLabelNode)
			for (const varLabelNode of varLabelNodes) {
				varLabelNode.markDirty()
			}
		})
	}

	const removeRootListener = editor.registerRootListener((nextRoot) => {
		if (!nextRoot) return
		requestAnimationFrame(() => {
			refreshVarLabelDecorators()
		})
	})

	requestAnimationFrame(() => {
		refreshVarLabelDecorators()
	})

	onUnmounted(() => {
		removeRootListener()
		removeTransform()
	})
})
</script>

<template />
