import { useLexicalComposerContext } from "@lexical/react/LexicalComposerContext";
import { mergeRegister } from "@lexical/utils";
import { SELECTION_CHANGE_COMMAND, TextNode } from "lexical";
import { useEffect } from "react";
import { $createTermIconNode, $createTermMarkerNode, $createTermNode, $isTermIconNode, $isTermMarkerNode, $isTermNode, TermIconNode, TermMarkerNode, TermNode } from "../nodes/term_node";

const TERM_REGEX = /\[\[(.+)\]\]/;

export function TermPlugin() {
    const [editor] = useLexicalComposerContext();

    useEffect(() => mergeRegister(
        editor.registerNodeTransform(TextNode, (node) => {
            const content = node.getTextContent();
            const matches = content.match(TERM_REGEX);
            if (!matches) return;

            const term = matches[1]!;

            const start = content.indexOf(matches[0]);
            const end = start + matches[0].length;

            const startIndex = start > 0 ? 1 : 0;
            const contentIndex = startIndex + 1;
            const endIndex = contentIndex + 1;

            const textNodes = node.splitText(start, start + 2, end - 2, end);

            const termNode = $createTermNode(term);
            textNodes[startIndex]!.insertBefore(termNode);

            const iconNode = $createTermIconNode(term);
            termNode.append(iconNode);
            const startMarkerNode = $createTermMarkerNode();
            startMarkerNode.append(textNodes[startIndex]!);
            const endMarkerNode = $createTermMarkerNode();
            endMarkerNode.append(textNodes[endIndex]!);

            termNode.append(startMarkerNode, textNodes[contentIndex]!, endMarkerNode);

            editor.dispatchCommand(SELECTION_CHANGE_COMMAND, undefined);
        }),
        editor.registerNodeTransform(TermMarkerNode, (node) => {
            const termNode = node.getParent();
            if ($isTermNode(termNode)) return;

            node.getChildren().reverse().forEach((child) => node.insertAfter(child));
            node.remove();
        }),
        editor.registerNodeTransform(TermIconNode, (node) => {
            const termNode = node.getParent();
            if ($isTermNode(termNode)) return;

            node.remove();
        }),
        editor.registerNodeTransform(TermNode, (node) => {
            const children = node.getChildren();
            const content = node.getTextContent();
            const term = node.getTerm();

            const iconNode = children.at(0);
            const startMarkerNode = children.at(1);
            const endMarkerNode = children.at(-1);

            if ($isTermIconNode(iconNode) &&
                $isTermMarkerNode(startMarkerNode) &&
                $isTermMarkerNode(endMarkerNode) &&
                iconNode.getTerm() === term &&
                startMarkerNode.getTextContent() === "[[" &&
                endMarkerNode.getTextContent() === "]]" &&
                content === `[[${term}]]`
            ) {
                return
            }


            node.getChildren().reverse().forEach((child) => node.insertAfter(child));
            node.remove();
        }),
    ));

    return null;
}
