import { $isAutoLinkNode, $isLinkNode, TOGGLE_LINK_COMMAND } from '@lexical/link';
import { useLexicalComposerContext } from '@lexical/react/LexicalComposerContext';
import { $findMatchingParent, mergeRegister } from '@lexical/utils';
import { $getSelection, $isRangeSelection, CLICK_COMMAND, COMMAND_PRIORITY_CRITICAL, COMMAND_PRIORITY_HIGH, COMMAND_PRIORITY_LOW, KEY_ESCAPE_COMMAND, SELECTION_CHANGE_COMMAND, } from 'lexical';
import { useCallback, useEffect, useRef, useState } from 'react';
import * as React from 'react';
import { createPortal } from 'react-dom';
import { getSelectedNode } from '../../utils/getSelectedNode';
import { setFloatingElemPositionForLinkEditor } from '../../utils/setFloatingElemPositionForLinkEditor';
import { sanitizeUrl } from '../../utils/url';
function FloatingLinkEditor({ anchorElem, editor, isLink, isLinkEditMode, setIsLink, setIsLinkEditMode, }) {
    const editorRef = useRef(null);
    const inputRef = useRef(null);
    const [linkUrl, setLinkUrl] = useState('');
    const [editedLinkUrl, setEditedLinkUrl] = useState('https://');
    const [lastSelection, setLastSelection] = useState(null);
    const updateLinkEditor = useCallback(() => {
        var _a, _b;
        const selection = $getSelection();
        if ($isRangeSelection(selection)) {
            const node = getSelectedNode(selection);
            const linkParent = $findMatchingParent(node, $isLinkNode);
            if (linkParent) {
                setLinkUrl(linkParent.getURL());
            }
            else if ($isLinkNode(node)) {
                setLinkUrl(node.getURL());
            }
            else {
                setLinkUrl('');
            }
        }
        const editorElem = editorRef.current;
        const nativeSelection = window.getSelection();
        const activeElement = document.activeElement;
        if (editorElem === null) {
            return;
        }
        const rootElement = editor.getRootElement();
        if (selection !== null &&
            nativeSelection !== null &&
            rootElement !== null &&
            rootElement.contains(nativeSelection.anchorNode) &&
            editor.isEditable()) {
            const domRect = (_b = (_a = nativeSelection.focusNode) === null || _a === void 0 ? void 0 : _a.parentElement) === null || _b === void 0 ? void 0 : _b.getBoundingClientRect();
            if (domRect) {
                domRect.y += 40;
                setFloatingElemPositionForLinkEditor(domRect, editorElem, anchorElem);
            }
            setLastSelection(selection);
        }
        else if (!activeElement || activeElement.className !== 'link-input') {
            if (rootElement !== null) {
                setFloatingElemPositionForLinkEditor(null, editorElem, anchorElem);
            }
            setLastSelection(null);
            setIsLinkEditMode(false);
            setLinkUrl('');
        }
        return true;
    }, [anchorElem, editor, setIsLinkEditMode]);
    useEffect(() => {
        const scrollerElem = anchorElem.parentElement;
        const update = () => {
            editor.getEditorState().read(() => {
                updateLinkEditor();
            });
        };
        window.addEventListener('resize', update);
        if (scrollerElem) {
            scrollerElem.addEventListener('scroll', update);
        }
        return () => {
            window.removeEventListener('resize', update);
            if (scrollerElem) {
                scrollerElem.removeEventListener('scroll', update);
            }
        };
    }, [anchorElem.parentElement, editor, updateLinkEditor]);
    useEffect(() => mergeRegister(editor.registerUpdateListener(({ editorState }) => {
        editorState.read(() => {
            updateLinkEditor();
        });
    }), editor.registerCommand(SELECTION_CHANGE_COMMAND, () => {
        updateLinkEditor();
        return true;
    }, COMMAND_PRIORITY_LOW), editor.registerCommand(KEY_ESCAPE_COMMAND, () => {
        if (isLink) {
            setIsLink(false);
            return true;
        }
        return false;
    }, COMMAND_PRIORITY_HIGH)), [editor, updateLinkEditor, setIsLink, isLink]);
    useEffect(() => {
        editor.getEditorState().read(() => {
            updateLinkEditor();
        });
    }, [editor, updateLinkEditor]);
    useEffect(() => {
        if (isLinkEditMode && inputRef.current) {
            inputRef.current.focus();
        }
    }, [isLinkEditMode, isLink]);
    const monitorInputInteraction = (event) => {
        if (event.key === 'Enter') {
            event.preventDefault();
            // eslint-disable-next-line no-use-before-define
            handleLinkSubmission();
        }
        else if (event.key === 'Escape') {
            event.preventDefault();
            setIsLinkEditMode(false);
        }
    };
    const handleLinkSubmission = () => {
        if (lastSelection !== null) {
            if (linkUrl !== '') {
                editor.dispatchCommand(TOGGLE_LINK_COMMAND, sanitizeUrl(editedLinkUrl));
            }
            setEditedLinkUrl('https://');
            setIsLinkEditMode(false);
        }
    };
    return (React.createElement("div", { ref: editorRef, className: 'link-editor' }, !isLink ? null : isLinkEditMode ? (React.createElement(React.Fragment, null,
        React.createElement("input", { ref: inputRef, className: 'link-input', onChange: (event) => {
                setEditedLinkUrl(event.target.value);
            }, onKeyDown: (event) => {
                monitorInputInteraction(event);
            }, value: editedLinkUrl }),
        React.createElement("div", null,
            React.createElement("div", { className: 'link-cancel', onClick: () => {
                    setIsLinkEditMode(false);
                }, onMouseDown: (event) => event.preventDefault(), role: 'button', tabIndex: 0 }),
            React.createElement("div", { className: 'link-confirm', onClick: handleLinkSubmission, onMouseDown: (event) => event.preventDefault(), role: 'button', tabIndex: 0 })))) : (React.createElement("div", { className: 'link-view' },
        React.createElement("a", { href: sanitizeUrl(linkUrl), rel: 'noopener noreferrer', target: '_blank' }, linkUrl),
        React.createElement("div", { className: 'link-edit', onClick: () => {
                setEditedLinkUrl(linkUrl);
                setIsLinkEditMode(true);
            }, onMouseDown: (event) => event.preventDefault(), role: 'button', tabIndex: 0 }),
        React.createElement("div", { className: 'link-trash', onClick: () => {
                editor.dispatchCommand(TOGGLE_LINK_COMMAND, null);
            }, onMouseDown: (event) => event.preventDefault(), role: 'button', tabIndex: 0 })))));
}
function useFloatingLinkEditorToolbar(editor, anchorElem, isLinkEditMode, setIsLinkEditMode) {
    const [activeEditor, setActiveEditor] = useState(editor);
    const [isLink, setIsLink] = useState(false);
    useEffect(() => {
        function updateToolbar() {
            const selection = $getSelection();
            if ($isRangeSelection(selection)) {
                const node = getSelectedNode(selection);
                const linkParent = $findMatchingParent(node, $isLinkNode);
                const autoLinkParent = $findMatchingParent(node, $isAutoLinkNode);
                // We don't want this menu to open for auto links.
                if (linkParent !== null && autoLinkParent === null) {
                    setIsLink(true);
                }
                else {
                    setIsLink(false);
                }
            }
        }
        return mergeRegister(editor.registerUpdateListener(({ editorState }) => {
            editorState.read(() => {
                updateToolbar();
            });
        }), editor.registerCommand(SELECTION_CHANGE_COMMAND, (_payload, newEditor) => {
            updateToolbar();
            setActiveEditor(newEditor);
            return false;
        }, COMMAND_PRIORITY_CRITICAL), editor.registerCommand(CLICK_COMMAND, (payload) => {
            const selection = $getSelection();
            if ($isRangeSelection(selection)) {
                const node = getSelectedNode(selection);
                const linkNode = $findMatchingParent(node, $isLinkNode);
                if ($isLinkNode(linkNode) && (payload.metaKey || payload.ctrlKey)) {
                    window.open(linkNode.getURL(), '_blank');
                    return true;
                }
            }
            return false;
        }, COMMAND_PRIORITY_LOW));
    }, [editor]);
    return createPortal(React.createElement(FloatingLinkEditor, { anchorElem: anchorElem, editor: activeEditor, isLink: isLink, isLinkEditMode: isLinkEditMode, setIsLink: setIsLink, setIsLinkEditMode: setIsLinkEditMode }), anchorElem);
}
export default function FloatingLinkEditorPlugin({ anchorElem = document.body, isLinkEditMode, setIsLinkEditMode, }) {
    const [editor] = useLexicalComposerContext();
    return useFloatingLinkEditorToolbar(editor, anchorElem, isLinkEditMode, setIsLinkEditMode);
}
//# sourceMappingURL=index.js.map