"use client";
import { useCallback, useEffect, useRef } from "react";
import { $createCodeNode, $isCodeNode } from "@lexical/code";
import { $convertFromMarkdownString, $convertToMarkdownString } from "@lexical/markdown";
import { useLexicalComposerContext } from "@lexical/react/LexicalComposerContext";
import { $getRoot, RootNode } from "lexical";
import { APPLY_VALUE_TAG } from "../constants.js";
import { useMarkdownMode } from "../context/markdown-mode-context.js";
import { BYLINE_TRANSFORMERS } from "../markdown/transformers.js";
const MARKDOWN_LANGUAGE = 'markdown';
function normalize(markdown) {
    return markdown.replace(/\n+$/, '');
}
function useMarkdownToggle() {
    const [editor] = useLexicalComposerContext();
    const { isMarkdown, setIsMarkdown, markdownModeRef } = useMarkdownMode();
    const originalEditorStateRef = useRef(null);
    const originalMarkdownRef = useRef('');
    const unregisterTransformRef = useRef(null);
    const registerRootGuard = useCallback(()=>{
        unregisterTransformRef.current?.();
        unregisterTransformRef.current = editor.registerNodeTransform(RootNode, (rootNode)=>{
            let codeNode = rootNode.getChildren().find($isCodeNode);
            if (null == codeNode) codeNode = $createCodeNode(MARKDOWN_LANGUAGE);
            if (1 !== rootNode.getChildrenSize() || null == codeNode.getParent()) {
                rootNode.splice(0, rootNode.getChildrenSize(), [
                    codeNode
                ]);
                codeNode.selectEnd();
            }
            if (codeNode.getLanguage() !== MARKDOWN_LANGUAGE) codeNode.setLanguage(MARKDOWN_LANGUAGE);
        });
    }, [
        editor
    ]);
    const clearRootGuard = useCallback(()=>{
        unregisterTransformRef.current?.();
        unregisterTransformRef.current = null;
    }, []);
    const enterMarkdown = useCallback(()=>{
        originalEditorStateRef.current = editor.getEditorState();
        markdownModeRef.current = true;
        editor.update(()=>{
            const markdown = $convertToMarkdownString(BYLINE_TRANSFORMERS, void 0, true);
            originalMarkdownRef.current = markdown;
            const codeNode = $createCodeNode(MARKDOWN_LANGUAGE);
            $getRoot().clear().append(codeNode);
            codeNode.select().insertRawText(markdown);
        });
        registerRootGuard();
        setIsMarkdown(true);
    }, [
        editor,
        markdownModeRef,
        registerRootGuard,
        setIsMarkdown
    ]);
    const exitMarkdown = useCallback(()=>{
        clearRootGuard();
        let currentMarkdown = '';
        editor.read(()=>{
            const first = $getRoot().getFirstChild();
            currentMarkdown = $isCodeNode(first) ? first.getTextContent() : $getRoot().getTextContent();
        });
        const edited = normalize(currentMarkdown) !== normalize(originalMarkdownRef.current);
        if (edited || null == originalEditorStateRef.current) {
            markdownModeRef.current = false;
            editor.update(()=>{
                $convertFromMarkdownString(currentMarkdown, BYLINE_TRANSFORMERS, void 0, true);
            });
        } else {
            editor.setEditorState(originalEditorStateRef.current, {
                tag: APPLY_VALUE_TAG
            });
            markdownModeRef.current = false;
        }
        originalEditorStateRef.current = null;
        originalMarkdownRef.current = '';
        setIsMarkdown(false);
    }, [
        editor,
        clearRootGuard,
        markdownModeRef,
        setIsMarkdown
    ]);
    const toggleMarkdown = useCallback(()=>{
        if (markdownModeRef.current) exitMarkdown();
        else enterMarkdown();
    }, [
        markdownModeRef,
        enterMarkdown,
        exitMarkdown
    ]);
    useEffect(()=>()=>clearRootGuard(), [
        clearRootGuard
    ]);
    return {
        isMarkdown,
        toggleMarkdown
    };
}
export { useMarkdownToggle };
