import { jsx as _jsx } from "react/jsx-runtime";
import { Suspense, useCallback, useEffect, useRef } from 'react';
import { $getNodeByKey, $getSelection, $isNodeSelection, $setSelection, CLICK_COMMAND, COMMAND_PRIORITY_LOW, DecoratorNode, KEY_BACKSPACE_COMMAND, KEY_DELETE_COMMAND, KEY_ENTER_COMMAND, KEY_ESCAPE_COMMAND, SELECTION_CHANGE_COMMAND, TextNode } from 'lexical';
import { useLexicalComposerContext } from '@lexical/react/LexicalComposerContext';
import { useLexicalNodeSelection } from '@lexical/react/useLexicalNodeSelection';
import { mergeRegister } from '@lexical/utils';
const imageCache = new Set();
function useSuspenseImage(src) {
    if (!imageCache.has(src)) {
        throw new Promise((resolve) => {
            const img = new Image();
            img.src = src;
            img.onload = () => {
                imageCache.add(src);
                resolve();
            };
        });
    }
}
function LazyImage({ altText, className, imageRef, src, width, height, maxWidth }) {
    useSuspenseImage(src);
    return (_jsx("img", { className: className, src: src, alt: altText, ref: imageRef, style: {
            height: `${height}${height === 'inherit' ? '' : 'px'}`,
            maxWidth,
            width: `${width}${width === 'inherit' ? '' : 'px'}`
        } }));
}
function ImageComponent({ src, altText, nodeKey, maxWidth }) {
    const imageRef = useRef(null);
    const buttonRef = useRef(null);
    const [isSelected, setSelected, clearSelection] = useLexicalNodeSelection(nodeKey);
    const [editor] = useLexicalComposerContext();
    const activeEditorRef = useRef(null);
    const onDelete = useCallback((payload) => {
        if (isSelected && $isNodeSelection($getSelection())) {
            const event = payload;
            event.preventDefault();
            const node = $getNodeByKey(nodeKey);
            if ($isImageNode(node)) {
                node.remove();
            }
            setSelected(false);
        }
        return false;
    }, [isSelected, nodeKey, setSelected]);
    const onEnter = useCallback((event) => {
        const latestSelection = $getSelection();
        const buttonElem = buttonRef.current;
        if (isSelected && $isNodeSelection(latestSelection) && latestSelection.getNodes().length === 1) {
            if (buttonElem !== null && buttonElem !== document.activeElement) {
                event.preventDefault();
                buttonElem.focus();
                return true;
            }
        }
        return false;
    }, [isSelected]);
    const onEscape = useCallback((event) => {
        if (buttonRef.current === event.target) {
            $setSelection(null);
            editor.update(() => {
                setSelected(true);
                const parentRootElement = editor.getRootElement();
                if (parentRootElement !== null) {
                    parentRootElement.focus();
                }
            });
            return true;
        }
        return false;
    }, [editor, setSelected]);
    useEffect(() => {
        const unregister = mergeRegister(editor.registerCommand(SELECTION_CHANGE_COMMAND, (_, activeEditor) => {
            activeEditorRef.current = activeEditor;
            return false;
        }, COMMAND_PRIORITY_LOW), editor.registerCommand(CLICK_COMMAND, (payload) => {
            const event = payload;
            if (event.target === imageRef.current) {
                if (event.shiftKey) {
                    setSelected(!isSelected);
                }
                else {
                    clearSelection();
                    setSelected(true);
                }
                return true;
            }
            return false;
        }, COMMAND_PRIORITY_LOW), editor.registerCommand(KEY_DELETE_COMMAND, onDelete, COMMAND_PRIORITY_LOW), editor.registerCommand(KEY_BACKSPACE_COMMAND, onDelete, COMMAND_PRIORITY_LOW), editor.registerCommand(KEY_ENTER_COMMAND, onEnter, COMMAND_PRIORITY_LOW), editor.registerCommand(KEY_ESCAPE_COMMAND, onEscape, COMMAND_PRIORITY_LOW));
        return () => {
            unregister();
        };
    }, [clearSelection, editor, isSelected, nodeKey, onDelete, onEnter, onEscape, setSelected]);
    return (_jsx(Suspense, Object.assign({ fallback: null }, { children: _jsx(LazyImage, { className: isSelected ? `selected` : null, src: src, altText: altText, imageRef: imageRef, maxWidth: maxWidth }) })));
}
function convertImageElement(domNode) {
    if (domNode instanceof HTMLImageElement) {
        const { alt: altText, src } = domNode;
        const node = $createImageNode({ altText, src, maxWidth: '100%' });
        return { node };
    }
    return null;
}
// eslint-disable-next-line @typescript-eslint/ban-ts-ignore
// @ts-ignore
export class ImageNode extends DecoratorNode {
    constructor(src, altText, maxWidth, key) {
        super(key);
        this.__src = src;
        this.__altText = altText;
        this.__maxWidth = maxWidth;
    }
    static getType() {
        return 'image';
    }
    static clone(node) {
        return new ImageNode(node.__src, node.__altText, node.__maxWidth, node.__key);
    }
    setWidthAndHeight(width, height) {
        const writable = this.getWritable();
        // eslint-disable-next-line @typescript-eslint/ban-ts-ignore
        // @ts-ignore
        writable.__width = width;
        // eslint-disable-next-line @typescript-eslint/ban-ts-ignore
        // @ts-ignore
        writable.__height = height;
    }
    // View
    createDOM(config) {
        const div = document.createElement('div');
        const theme = config.theme;
        const className = theme.image;
        if (className !== undefined) {
            div.className = className;
        }
        return div;
    }
    updateDOM() {
        return false;
    }
    static importDOM() {
        // eslint-disable-next-line @typescript-eslint/ban-ts-ignore
        // @ts-ignore
        const dom = TextNode.importDOM();
        return Object.assign({ img: (node) => ({
                conversion: convertImageElement,
                priority: 0
            }) }, dom);
    }
    exportDOM() {
        const element = document.createElement('img');
        element.setAttribute('src', this.__src);
        element.setAttribute('alt', this.__altText);
        element.setAttribute('style', `max-width: ${this.__maxWidth}px;`);
        return { element };
    }
    decorate() {
        return _jsx(ImageComponent, { src: this.__src, altText: this.__altText, maxWidth: this.__maxWidth, nodeKey: this.getKey() });
    }
    static importJSON(serializedNode) {
        const { altText, maxWidth, src } = serializedNode;
        const node = $createImageNode({
            altText,
            src,
            maxWidth
        });
        return node;
    }
    exportJSON() {
        return {
            // eslint-disable-next-line @typescript-eslint/ban-ts-ignore
            // @ts-ignore
            altText: this.getAltText(),
            maxWidth: this.__maxWidth,
            // eslint-disable-next-line @typescript-eslint/ban-ts-ignore
            // @ts-ignore
            src: this.getSrc(),
            type: 'image',
            version: 1
        };
    }
}
export function $createImageNode({ src, altText, maxWidth }) {
    return new ImageNode(src, altText, maxWidth);
}
export function $isImageNode(node) {
    return node.getType() === 'image';
}
