import {
    useEffect,
    useState,
    useCallback,
    useRef,
    createPortal,
    useMemo,
    useImperativeHandle,
    forwardRef,
    useId
} from '@wordpress/element';
import {__} from '@wordpress/i18n';
import {LexicalComposer} from '@lexical/react/LexicalComposer';
import {RichTextPlugin} from '@lexical/react/LexicalRichTextPlugin';
import {ContentEditable} from '@lexical/react/LexicalContentEditable';
import {HistoryPlugin} from '@lexical/react/LexicalHistoryPlugin';
import {AutoFocusPlugin} from '@lexical/react/LexicalAutoFocusPlugin';
import {LexicalErrorBoundary} from '@lexical/react/LexicalErrorBoundary';
import {HeadingNode, QuoteNode} from '@lexical/rich-text';
import {ListItemNode, ListNode} from '@lexical/list';
import {LinkNode, AutoLinkNode} from '@lexical/link';
import {CodeNode, CodeHighlightNode} from '@lexical/code';
import {
    TableNode,
    TableCellNode,
    TableRowNode,
    $createTableCellNode,
    $createTableNode,
    $createTableRowNode
} from '@lexical/table';
import {TablePlugin} from '@lexical/react/LexicalTablePlugin';
import {ListPlugin} from '@lexical/react/LexicalListPlugin';
import {LinkPlugin} from '@lexical/react/LexicalLinkPlugin';
import {useLexicalComposerContext} from '@lexical/react/LexicalComposerContext';
import {$generateHtmlFromNodes, $generateNodesFromDOM} from '@lexical/html';
import {
    $getSelection,
    $isRangeSelection,
    FORMAT_TEXT_COMMAND,
    $createParagraphNode,
    $getRoot,
    $insertNodes,
    $createTextNode,
    DecoratorNode,
    NodeKey
} from 'lexical';
import {$setBlocksType} from '@lexical/selection';
import {$createHeadingNode, $isHeadingNode} from '@lexical/rich-text';
import {
    INSERT_ORDERED_LIST_COMMAND,
    INSERT_UNORDERED_LIST_COMMAND,
    $isListNode
} from '@lexical/list';
import {TOGGLE_LINK_COMMAND} from '@lexical/link';
import TurndownService from 'turndown';
import {marked} from 'marked';
import Emoji from '../../button/emoji';
import useClickOutside from '../../../../components/hooks/use-click-outside';
import InsertLink from '../../popups/insert-link';

// Image Node for Lexical
class ImageNode extends DecoratorNode {
    __src;
    __alt;
    __title;
    __width;
    __height;

    static getType() {
        return 'image';
    }

    static clone(node) {
        return new ImageNode(
            node.__src,
            node.__alt,
            node.__title,
            node.__width,
            node.__height,
            node.__key
        );
    }

    constructor(src, alt, title, width, height, key) {
        super(key);
        this.__src = src || '';
        this.__alt = alt || '';
        this.__title = title || '';
        this.__width = width || null;
        this.__height = height || null;
    }

    createDOM(config) {
        const img = document.createElement('img');
        img.src = this.__src;
        img.alt = this.__alt;
        if (this.__title) {
            img.title = this.__title;
        }
        if (this.__width) {
            img.width = this.__width;
        }
        if (this.__height) {
            img.height = this.__height;
        }
        img.className = 'lbaic-settings-lexical-image';
        img.style.maxWidth = '100%';
        img.style.height = 'auto';
        img.style.display = 'block';
        return img;
    }

    updateDOM(prevNode, dom) {
        if (prevNode.__src !== this.__src) {
            dom.src = this.__src;
        }
        if (prevNode.__alt !== this.__alt) {
            dom.alt = this.__alt;
        }
        if (prevNode.__title !== this.__title) {
            dom.title = this.__title || '';
        }
        if (prevNode.__width !== this.__width) {
            if (this.__width) {
                dom.width = this.__width;
            } else {
                dom.removeAttribute('width');
            }
        }
        if (prevNode.__height !== this.__height) {
            if (this.__height) {
                dom.height = this.__height;
            } else {
                dom.removeAttribute('height');
            }
        }
        return false;
    }

    static importDOM() {
        return {
            img: (node) => {
                // Return conversion function for img elements
                return {
                    conversion: convertImageElement,
                    priority: 1, // Higher priority to ensure images are converted
                };
            },
        };
    }

    exportDOM() {
        const img = document.createElement('img');
        img.setAttribute('src', this.__src);
        img.setAttribute('alt', this.__alt);
        if (this.__title) {
            img.setAttribute('title', this.__title);
        }
        if (this.__width) {
            img.setAttribute('width', this.__width);
        }
        if (this.__height) {
            img.setAttribute('height', this.__height);
        }
        return {element: img};
    }

    static importJSON(serializedNode) {
        const {src, alt, title, width, height} = serializedNode;
        return $createImageNode(src, alt, title, width, height);
    }

    exportJSON() {
        return {
            src: this.__src,
            alt: this.__alt,
            title: this.__title,
            width: this.__width,
            height: this.__height,
            type: 'image',
            version: 1,
        };
    }

    getSrc() {
        return this.__src;
    }

    getAlt() {
        return this.__alt;
    }

    getTitle() {
        return this.__title;
    }

    setSrc(src) {
        const writable = this.getWritable();
        writable.__src = src;
    }

    setAlt(alt) {
        const writable = this.getWritable();
        writable.__alt = alt;
    }

    setTitle(title) {
        const writable = this.getWritable();
        writable.__title = title;
    }
}

function convertImageElement(domNode) {
    // Handle both Element and regular DOM node
    const getAttr = (node, attr) => {
        if (node.getAttribute) {
            return node.getAttribute(attr);
        }
        return node[attr] || null;
    };

    const src = getAttr(domNode, 'src') || '';
    const alt = getAttr(domNode, 'alt') || '';
    const title = getAttr(domNode, 'title') || '';
    const width = getAttr(domNode, 'width');
    const height = getAttr(domNode, 'height');

    // Normalize protocol-relative URLs (//example.com -> https://example.com)
    const normalizedSrc = src.startsWith('//') ? `https:${src}` : src;

    const node = $createImageNode(
        normalizedSrc,
        alt,
        title,
        width ? parseInt(width, 10) : null,
        height ? parseInt(height, 10) : null
    );
    return {node};
}

function $createImageNode(src, alt, title, width, height) {
    return new ImageNode(src, alt, title, width, height);
}

function $isImageNode(node) {
    return node instanceof ImageNode;
}

// Helper function to process HTML and convert markdown images inside HTML to img tags
function processMarkdownImagesInHTML(bodyElement) {
    // Improved regex that handles nested brackets in alt text by matching from ![ to ]( and then the URL
    // This pattern: !\[ matches the opening, then we capture everything until we find ]( followed by the URL
    const imageRegex = /!\[([^\]]*(?:\[[^\]]*\][^\]]*)*)\]\(([^)]+)\)/g;

    const walker = document.createTreeWalker(
        bodyElement,
        NodeFilter.SHOW_TEXT,
        null
    );
    const textNodes = [];
    let textNode;
    while (textNode = walker.nextNode()) {
        const text = textNode.textContent;
        // Reset regex for each test
        imageRegex.lastIndex = 0;
        if (imageRegex.test(text)) {
            textNodes.push(textNode);
        }
    }

    // Replace markdown images in text nodes with img elements
    textNodes.forEach((textNode) => {
        const text = textNode.textContent;
        const matches = [];
        let match;
        imageRegex.lastIndex = 0; // Reset regex

        // Use a more robust approach: find ![, then find the matching ](, then find the URL
        let searchIndex = 0;
        while (searchIndex < text.length) {
            const imgStart = text.indexOf('![', searchIndex);
            if (imgStart === -1) break;

            // Find the matching ]( - we need to handle nested brackets
            let bracketCount = 0;
            let altEnd = -1;
            let urlStart = -1;

            for (let i = imgStart + 2; i < text.length; i++) {
                if (text[i] === '[') {
                    bracketCount++;
                } else if (text[i] === ']') {
                    if (bracketCount === 0) {
                        altEnd = i;
                        // Check if next is (
                        if (i + 1 < text.length && text[i + 1] === '(') {
                            urlStart = i + 2;
                            break;
                        }
                    } else {
                        bracketCount--;
                    }
                }
            }

            if (altEnd !== -1 && urlStart !== -1) {
                // Find the closing ) for the URL
                const urlEnd = text.indexOf(')', urlStart);
                if (urlEnd !== -1) {
                    const alt = text.substring(imgStart + 2, altEnd);
                    const src = text.substring(urlStart, urlEnd);
                    const fullMatch = text.substring(imgStart, urlEnd + 1);

                    matches.push({
                        fullMatch: fullMatch,
                        alt: alt || '',
                        src: src || '',
                        index: imgStart
                    });

                    searchIndex = urlEnd + 1;
                } else {
                    searchIndex = imgStart + 2;
                }
            } else {
                searchIndex = imgStart + 2;
            }
        }

        if (matches.length > 0) {
            const fragment = document.createDocumentFragment();
            let lastIndex = 0;

            matches.forEach((imgMatch) => {
                // Add text before image
                if (imgMatch.index > lastIndex) {
                    const textBefore = text.substring(lastIndex, imgMatch.index);
                    if (textBefore.trim()) {
                        fragment.appendChild(document.createTextNode(textBefore));
                    }
                }

                // Create img element
                const imgEl = document.createElement('img');
                let src = imgMatch.src.trim();
                // Normalize protocol-relative URLs
                if (src.startsWith('//')) {
                    src = `https:${src}`;
                }
                imgEl.src = src;
                imgEl.alt = imgMatch.alt.trim();
                fragment.appendChild(imgEl);

                lastIndex = imgMatch.index + imgMatch.fullMatch.length;
            });

            // Add remaining text
            if (lastIndex < text.length) {
                const textAfter = text.substring(lastIndex);
                if (textAfter.trim()) {
                    fragment.appendChild(document.createTextNode(textAfter));
                }
            }

            // Replace text node with fragment
            if (fragment.childNodes.length > 0) {
                textNode.parentNode.replaceChild(fragment, textNode);
            }
        }
    });
}

// Helper function to parse markdown images from text, handling nested brackets in alt text
function parseMarkdownImages(text) {
    const imageMatches = [];
    let searchIndex = 0;

    while (searchIndex < text.length) {
        const imgStart = text.indexOf('![', searchIndex);
        if (imgStart === -1) break;

        // Find the matching ]( - we need to handle nested brackets
        let bracketCount = 0;
        let altEnd = -1;
        let urlStart = -1;

        for (let i = imgStart + 2; i < text.length; i++) {
            if (text[i] === '[') {
                bracketCount++;
            } else if (text[i] === ']') {
                if (bracketCount === 0) {
                    altEnd = i;
                    // Check if next is (
                    if (i + 1 < text.length && text[i + 1] === '(') {
                        urlStart = i + 2;
                        break;
                    }
                } else {
                    bracketCount--;
                }
            }
        }

        if (altEnd !== -1 && urlStart !== -1) {
            // Find the closing ) for the URL
            const urlEnd = text.indexOf(')', urlStart);
            if (urlEnd !== -1) {
                const alt = text.substring(imgStart + 2, altEnd);
                let src = text.substring(urlStart, urlEnd);
                // Normalize protocol-relative URLs
                if (src.startsWith('//')) {
                    src = `https:${src}`;
                }
                const fullMatch = text.substring(imgStart, urlEnd + 1);

                imageMatches.push({
                    alt: alt.trim(),
                    src: src.trim(),
                    start: imgStart,
                    end: urlEnd + 1,
                    fullMatch: fullMatch
                });

                searchIndex = urlEnd + 1;
            } else {
                searchIndex = imgStart + 2;
            }
        } else {
            searchIndex = imgStart + 2;
        }
    }

    return imageMatches;
}

// Helper function to extract images from paragraphs
function extractImagesFromParagraphs(bodyElement) {
    const images = Array.from(bodyElement.querySelectorAll('img'));
    images.forEach((img) => {
        const parent = img.parentElement;
        if (parent && parent.tagName === 'P') {
            // Check if paragraph only contains whitespace and the image
            const hasOnlyImage = Array.from(parent.childNodes).every(node => {
                if (node === img) return true;
                if (node.nodeType === Node.TEXT_NODE) {
                    return !node.textContent.trim();
                }
                return false;
            });

            // Create a new image element with all attributes
            const imageNode = document.createElement('img');
            imageNode.src = img.src || img.getAttribute('src') || '';
            imageNode.alt = img.alt || img.getAttribute('alt') || '';
            const title = img.title || img.getAttribute('title');
            if (title) {
                imageNode.title = title;
            }
            const width = img.width || img.getAttribute('width');
            if (width) {
                imageNode.setAttribute('width', width);
            }
            const height = img.height || img.getAttribute('height');
            if (height) {
                imageNode.setAttribute('height', height);
            }

            // If image is the only content in paragraph (or only whitespace), replace paragraph
            if (hasOnlyImage) {
                parent.parentNode.replaceChild(imageNode, parent);
            } else {
                // Otherwise, insert image before paragraph and remove from paragraph
                parent.parentNode.insertBefore(imageNode, parent);
                parent.removeChild(img);
            }
        }
    });
}

// Editor theme configuration
const theme = {
    paragraph: 'lbaic-settings-lexical-paragraph',
    quote: 'lbaic-settings-lexical-quote',
    heading: {
        h1: 'lbaic-settings-lexical-h1',
        h2: 'lbaic-settings-lexical-h2',
        h3: 'lbaic-settings-lexical-h3',
    },
    list: {
        nested: {
            listitem: 'lbaic-settings-lexical-listitem-nested',
        },
        ol: 'lbaic-settings-lexical-ol',
        ul: 'lbaic-settings-lexical-ul',
        listitem: 'lbaic-settings-lexical-listitem',
    },
    text: {
        bold: 'lbaic-settings-lexical-text-bold',
        italic: 'lbaic-settings-lexical-text-italic',
        strikethrough: 'lbaic-settings-lexical-text-strikethrough',
        underline: 'lbaic-settings-lexical-text-underline',
        code: 'lbaic-settings-lexical-text-code',
    },
    link: 'lbaic-settings-lexical-link',
    code: 'lbaic-settings-lexical-code-block',
    image: 'lbaic-settings-lexical-image',
};

// OnChange Plugin to sync editor state with parent component
function OnChangePlugin({onChange, convertToMarkdown, turndown, hasBeenTouchedRef, isInitialLoadRef}) {
    const [editor] = useLexicalComposerContext();
    const onChangeRef = useRef(onChange);
    const convertToMarkdownRef = useRef(convertToMarkdown);
    const turndownRef = useRef(turndown);

    // Keep refs updated
    useEffect(() => {
        onChangeRef.current = onChange;
        convertToMarkdownRef.current = convertToMarkdown;
        turndownRef.current = turndown;
    });

    useEffect(() => {
        // Track if this is the first update to skip initial render
        let isFirstUpdate = true;
        let lastHtmlString = '';

        return editor.registerUpdateListener(({editorState, dirtyElements, dirtyLeaves}) => {
            // Check if this is a user-initiated change (has dirty elements/leaves)
            const isUserChange = dirtyElements.size > 0 || dirtyLeaves.size > 0;

            // Skip the first update (initial load) ONLY if it's not a user change
            if (isFirstUpdate) {
                isFirstUpdate = false;
                if (isInitialLoadRef) {
                    isInitialLoadRef.current = false;
                }
                // Store initial HTML to compare later
                editorState.read(() => {
                    lastHtmlString = $generateHtmlFromNodes(editor, null);
                });

                // Only skip if this is not a user-initiated change (i.e., just initial render)
                if (!isUserChange) {
                    return;
                }
            }

            // Convert editor state to HTML string
            editorState.read(() => {
                const htmlString = $generateHtmlFromNodes(editor, null);

                // Only update if HTML actually changed (prevents unnecessary updates)
                if (htmlString === lastHtmlString) {
                    return;
                }
                lastHtmlString = htmlString;

                // Mark as touched if this is a user-initiated change
                if (isUserChange && hasBeenTouchedRef) {
                    hasBeenTouchedRef.current = true;
                }

                // Convert to markdown if needed
                if (convertToMarkdownRef.current && turndownRef.current) {
                    let markdown = htmlString.trim() ? turndownRef.current.turndown(htmlString) : '';

                    // Remove unnecessary backslashes before underscores within variable patterns
                    // This prevents Turndown from escaping underscores in variables which should remain as-is
                    markdown = markdown.replace(/\{([^}]*?)\}/g, (match, varContent) => {
                        // Remove backslashes before underscores within the variable content
                        const cleanedContent = varContent.replace(/\\_/g, '_');
                        return `{${cleanedContent}}`;
                    });

                    // Always update value (for real-time sync), pass isUserChange for validation
                    onChangeRef.current(markdown, isUserChange);
                } else {
                    // Always update value (for real-time sync), pass isUserChange for validation
                    onChangeRef.current(htmlString, isUserChange);
                }
            });
        });
    }, [editor, hasBeenTouchedRef, isInitialLoadRef]); // Removed onChange, convertToMarkdown, turndown from deps

    return null;
}

// Toolbar Component
function ToolbarPlugin() {
    const [editor] = useLexicalComposerContext();
    const [isBold, setIsBold] = useState(false);
    const [isItalic, setIsItalic] = useState(false);
    const [isUnderline, setIsUnderline] = useState(false);
    const [blockType, setBlockType] = useState('paragraph');
    const [showBlockTypeMenu, setShowBlockTypeMenu] = useState(false);
    const [showLinkPopup, setShowLinkPopup] = useState(false);
    const emojiButtonRef = useRef(null);
    const blockTypeButtonRef = useRef(null);
    const blockTypeMenuRef = useRef(null);
    const metaBoxRef = useRef(document.getElementById('chatbot-meta-box'));
    const fieldMenuRef = useRef(document.getElementById('lbaic-settings-field-menu'));
    const [dropdownPosition, setDropdownPosition] = useState({
        top: 0,
        left: 0,
    });

    // Close dropdown when clicking outside
    useClickOutside([blockTypeMenuRef, blockTypeButtonRef], () => setShowBlockTypeMenu(false));

    // Update formatting states
    useEffect(() => {
        return editor.registerUpdateListener(({editorState}) => {
            editorState.read(() => {
                const selection = $getSelection();
                if ($isRangeSelection(selection)) {
                    setIsBold(selection.hasFormat('bold'));
                    setIsItalic(selection.hasFormat('italic'));
                    setIsUnderline(selection.hasFormat('underline'));

                    // Get block type
                    const anchorNode = selection.anchor.getNode();
                    const element = anchorNode.getKey() === 'root'
                        ? anchorNode
                        : anchorNode.getTopLevelElementOrThrow();

                    const elementKey = element.getKey();
                    const elementDOM = editor.getElementByKey(elementKey);

                    if (elementDOM !== null) {
                        if ($isHeadingNode(element)) {
                            const tag = element.getTag();
                            setBlockType(tag);
                        } else if ($isListNode(element)) {
                            const listType = element.getListType();
                            setBlockType(listType === 'number' ? 'ol' : 'ul');
                        } else {
                            setBlockType('paragraph');
                        }
                    }
                }
            });
        });
    }, [editor]);

    // Setup dropdown position
    useEffect(() => {
        if (showBlockTypeMenu) {
            setupDropdownPosition();
        }
        // Events
        window.addEventListener('resize', setupDropdownPosition);
        window.addEventListener('scroll', setupDropdownPosition, true);

        return () => {
            window.removeEventListener('resize', setupDropdownPosition);
            window.removeEventListener('scroll', setupDropdownPosition, true);
        };
    }, [showBlockTypeMenu]);

    /**
     * Setup dropdown position
     */
    const setupDropdownPosition = () => {
        if (blockTypeButtonRef.current && showBlockTypeMenu) {
            const rect = blockTypeButtonRef.current.getBoundingClientRect();
            const metaBoxRect = metaBoxRef.current ? metaBoxRef.current.getBoundingClientRect() : null;
            const fieldMenuRect = fieldMenuRef.current ? fieldMenuRef.current.getBoundingClientRect() : null;
            const topMenuHeight = document.getElementById('wpadminbar')?.offsetHeight || 0;

            // Calculate position relative to the field-menu container (where portal renders)
            let top = rect.bottom - (metaBoxRect?.top || topMenuHeight) + 4;
            let left = rect.left - (fieldMenuRect?.left || metaBoxRect?.left || 0);

            setDropdownPosition({
                top: top + 'px',
                left: left + 'px',
            });
        }
    };

    const formatBold = () => {
        editor.dispatchCommand(FORMAT_TEXT_COMMAND, 'bold');
    };

    const formatItalic = () => {
        editor.dispatchCommand(FORMAT_TEXT_COMMAND, 'italic');
    };

    const formatUnderline = () => {
        editor.dispatchCommand(FORMAT_TEXT_COMMAND, 'underline');
    };

    const insertLink = (url) => {
        if (url) {
            editor.dispatchCommand(TOGGLE_LINK_COMMAND, url);
        }
        setShowLinkPopup(false);
    };

    const insertOrderedList = () => {
        editor.dispatchCommand(INSERT_ORDERED_LIST_COMMAND, undefined);
    };

    const insertUnorderedList = () => {
        editor.dispatchCommand(INSERT_UNORDERED_LIST_COMMAND, undefined);
    };

    const formatBlockType = (type) => {
        editor.update(() => {
            const selection = $getSelection();
            if ($isRangeSelection(selection)) {
                if (type === 'paragraph') {
                    $setBlocksType(selection, () => $createParagraphNode());
                } else if (type === 'h1' || type === 'h2' || type === 'h3') {
                    $setBlocksType(selection, () => $createHeadingNode(type));
                }
            }
        });
        setShowBlockTypeMenu(false);
    };

    const onEmojiClick = (emojiObject) => {
        editor.update(() => {
            const selection = $getSelection();
            if ($isRangeSelection(selection)) {
                const emojiText = emojiObject.emoji;
                const textNode = $createTextNode(emojiText);
                selection.insertNodes([textNode]);
            }
        });
        editor.focus();
    };

    const getBlockTypeLabel = () => {
        const labels = {
            paragraph: __('Normal', 'limb-chatbot'),
            h1: __('Heading 1', 'limb-chatbot'),
            h2: __('Heading 2', 'limb-chatbot'),
            h3: __('Heading 3', 'limb-chatbot'),
            ol: __('Numbered List', 'limb-chatbot'),
            ul: __('Bullet List', 'limb-chatbot')
        };
        return labels[blockType] || __('Normal', 'limb-chatbot');
    };

    const getBlockTypeIcon = () => {
        const icons = {
            paragraph: 'paragraph',
            h1: 'h1',
            h2: 'h2',
            h3: 'h3',
            ol: 'list-ordered',
            ul: 'list-unordered'
        };
        return icons[blockType] || 'paragraph';
    };

    return (
        <div className="lbaic-settings-lexical-toolbar">
            <div className="lbaic-settings-lexical-toolbar-left">
                {/* Block Type Dropdown */}
                <div className="lbaic-settings-lexical-toolbar-dropdown" ref={blockTypeButtonRef}>
                    <button
                        onClick={() => setShowBlockTypeMenu(!showBlockTypeMenu)}
                        className="lbaic-settings-lexical-toolbar-dropdown-btn"
                        title={__('Block Type', 'limb-chatbot')}
                    >
                        <svg className="lbaic-settings-lexical-toolbar-icon" viewBox="0 0 16 16" fill="currentColor">
                            <use href={`#lbaic-settings-${getBlockTypeIcon()}`}/>
                        </svg>
                        <span className="lbaic-settings-lexical-toolbar-dropdown-label">{getBlockTypeLabel()}</span>
                        <svg className="lbaic-settings-lexical-toolbar-icon-sm" viewBox="0 0 24 24" fill="currentColor">
                            <use href="#lbaic-settings-chevron-down"/>
                        </svg>
                    </button>
                </div>

                <div className="lbaic-settings-lexical-toolbar-separator"></div>

                {/* Bold */}
                <button
                    onClick={formatBold}
                    className={`lbaic-settings-lexical-toolbar-btn${isBold ? ' active' : ''}`}
                    title={__('Bold', 'limb-chatbot')}
                >
                    <svg className="lbaic-settings-lexical-toolbar-icon" viewBox="0 0 24 24" fill="currentColor">
                        <use href="#lbaic-settings-bold"/>
                    </svg>
                </button>

                {/* Italic */}
                <button
                    onClick={formatItalic}
                    className={`lbaic-settings-lexical-toolbar-btn${isItalic ? ' active' : ''}`}
                    title={__('Italic', 'limb-chatbot')}
                >
                    <svg className="lbaic-settings-lexical-toolbar-icon" viewBox="0 0 24 24" fill="currentColor">
                        <use href="#lbaic-settings-italic"/>
                    </svg>
                </button>

                {/* Underline */}
                <button
                    onClick={formatUnderline}
                    className={`lbaic-settings-lexical-toolbar-btn${isUnderline ? ' active' : ''}`}
                    title={__('Underline', 'limb-chatbot')}
                >
                    <svg className="lbaic-settings-lexical-toolbar-icon" viewBox="0 0 24 24" fill="currentColor">
                        <use href="#lbaic-settings-underline"/>
                    </svg>
                </button>

                <div className="lbaic-settings-lexical-toolbar-separator"></div>

                {/* Ordered List */}
                <button
                    onClick={insertOrderedList}
                    className="lbaic-settings-lexical-toolbar-btn"
                    title={__('Numbered List', 'limb-chatbot')}
                >
                    <svg className="lbaic-settings-lexical-toolbar-icon" viewBox="0 0 24 24" fill="currentColor">
                        <use href="#lbaic-settings-list-ordered"/>
                    </svg>
                </button>

                {/* Bullet List */}
                <button
                    onClick={insertUnorderedList}
                    className="lbaic-settings-lexical-toolbar-btn"
                    title={__('Bullet List', 'limb-chatbot')}
                >
                    <svg className="lbaic-settings-lexical-toolbar-icon" viewBox="0 0 24 24" fill="currentColor">
                        <use href="#lbaic-settings-list-unordered"/>
                    </svg>
                </button>

                <div className="lbaic-settings-lexical-toolbar-separator"></div>

                {/* Link */}
                <button
                    onClick={() => setShowLinkPopup(true)}
                    className="lbaic-settings-lexical-toolbar-btn"
                    title={__('Insert Link', 'limb-chatbot')}
                >
                    <svg className="lbaic-settings-lexical-toolbar-icon" viewBox="0 0 24 24" fill="currentColor">
                        <use href="#lbaic-settings-link-icon"/>
                    </svg>
                </button>

                <div className="lbaic-settings-lexical-toolbar-separator"></div>

                {/* Emoji */}
                <div ref={emojiButtonRef} className="lbaic-settings-lexical-toolbar-emoji">
                    <Emoji chosen={onEmojiClick}/>
                </div>
            </div>

            {/* Block Type Menu with Portal */}
            {showBlockTypeMenu && createPortal(
                <div
                    ref={blockTypeMenuRef}
                    className="lbaic-settings-lexical-toolbar-dropdown-menu"
                    style={{
                        '--lbaic-settings-dropdown-top': dropdownPosition.top,
                        '--lbaic-settings-dropdown-left': dropdownPosition.left,
                    }}
                >
                    <button
                        onClick={() => formatBlockType('paragraph')}
                        className="lbaic-settings-lexical-toolbar-dropdown-item"
                    >
                        <svg className="lbaic-settings-lexical-toolbar-dropdown-item-icon" viewBox="0 0 16 16"
                             fill="currentColor">
                            <use href="#lbaic-settings-paragraph"/>
                        </svg>
                        {__('Normal', 'limb-chatbot')}
                    </button>
                    <button
                        onClick={() => formatBlockType('h1')}
                        className="lbaic-settings-lexical-toolbar-dropdown-item lbaic-settings-lexical-toolbar-dropdown-item-h1"
                    >
                        <svg className="lbaic-settings-lexical-toolbar-dropdown-item-icon" viewBox="0 0 16 16"
                             fill="currentColor">
                            <use href="#lbaic-settings-h1"/>
                        </svg>
                        {__('Heading 1', 'limb-chatbot')}
                    </button>
                    <button
                        onClick={() => formatBlockType('h2')}
                        className="lbaic-settings-lexical-toolbar-dropdown-item lbaic-settings-lexical-toolbar-dropdown-item-h2"
                    >
                        <svg className="lbaic-settings-lexical-toolbar-dropdown-item-icon" viewBox="0 0 16 16"
                             fill="currentColor">
                            <use href="#lbaic-settings-h2"/>
                        </svg>
                        {__('Heading 2', 'limb-chatbot')}
                    </button>
                    <button
                        onClick={() => formatBlockType('h3')}
                        className="lbaic-settings-lexical-toolbar-dropdown-item lbaic-settings-lexical-toolbar-dropdown-item-h3"
                    >
                        <svg className="lbaic-settings-lexical-toolbar-dropdown-item-icon" viewBox="0 0 16 16"
                             fill="currentColor">
                            <use href="#lbaic-settings-h3"/>
                        </svg>
                        {__('Heading 3', 'limb-chatbot')}
                    </button>
                </div>,
                document.getElementById('lbaic-settings-field-menu')
            )}

            {/* Link Popup */}
            {showLinkPopup && (
                <InsertLink
                    inserted={insertLink}
                    close={() => setShowLinkPopup(false)}
                />
            )}
        </div>
    );
}

// Plugin to expose insertVariable method
function InsertVariablePlugin({insertVariableRef}) {
    const [editor] = useLexicalComposerContext();

    useImperativeHandle(insertVariableRef, () => ({
        insertVariable: (variable) => {
            if (!variable) return;

            editor.update(() => {
                const selection = $getSelection();
                if ($isRangeSelection(selection)) {
                    const textNode = $createTextNode(variable);
                    selection.insertNodes([textNode]);
                    // Move cursor after inserted text
                    textNode.select();
                } else {
                    // If no selection, insert at root
                    const root = $getRoot();
                    const textNode = $createTextNode(variable);
                    root.append(textNode);
                    textNode.select();
                }
            });

            editor.focus();
        }
    }), [editor]);

    return null;
}

// Plugin to sync external value changes to editor
function ValueSyncPlugin({value, marked, isInternalUpdateRef}) {
    const [editor] = useLexicalComposerContext();
    const prevValueRef = useRef(value);

    useEffect(() => {
        // Skip if this is an internal update (from our own onChange)
        if (isInternalUpdateRef?.current) {
            prevValueRef.current = value;
            // Reset the flag now that we've processed this internal update
            isInternalUpdateRef.current = false;
            return;
        }

        // Only update if value changed externally (not from our own onChange)
        if (value !== prevValueRef.current && value !== undefined && value !== null) {
            editor.update(() => {
                const root = $getRoot();
                const currentHtml = $generateHtmlFromNodes(editor, null);

                // Check if value looks like HTML (contains tags) or markdown
                const looksLikeHtml = /<[a-z][^>]*>[\s\S]*<\/[a-z]+>/i.test(value) ||
                    /<[a-z][^>]*\/>/i.test(value);

                if (!looksLikeHtml) {
                    // Process markdown - extract images and convert directly to ImageNodes
                    root.clear();

                    if (value.trim()) {
                        // Find all image markdown patterns: ![alt](src)
                        const imageMatches = parseMarkdownImages(value);

                        if (imageMatches.length === 0) {
                            // No images, parse normally
                            const parser = new DOMParser();
                            const htmlString = marked.parse(value);
                            const dom = parser.parseFromString(htmlString, 'text/html');
                            const bodyElement = dom.body;
                            const nodes = $generateNodesFromDOM(editor, bodyElement);
                            $insertNodes(nodes);
                        } else {
                            // Process content with images
                            let lastIndex = 0;

                            imageMatches.forEach((imgMatch) => {
                                // Add text content before this image
                                if (imgMatch.start > lastIndex) {
                                    const textBefore = value.substring(lastIndex, imgMatch.start);
                                    if (textBefore.trim()) {
                                        const parser = new DOMParser();
                                        const htmlString = marked.parse(textBefore);
                                        const dom = parser.parseFromString(htmlString, 'text/html');
                                        const bodyElement = dom.body;
                                        const nodes = $generateNodesFromDOM(editor, bodyElement);
                                        $insertNodes(nodes);
                                    }
                                }

                                // Add the image node
                                const imageNode = $createImageNode(imgMatch.src, imgMatch.alt, '', null, null);
                                root.append(imageNode);

                                // Add a paragraph after image for proper spacing
                                const paragraph = $createParagraphNode();
                                root.append(paragraph);

                                lastIndex = imgMatch.end;
                            });

                            // Add remaining text after last image
                            if (lastIndex < value.length) {
                                const textAfter = value.substring(lastIndex);
                                if (textAfter.trim()) {
                                    const parser = new DOMParser();
                                    const htmlString = marked.parse(textAfter);
                                    const dom = parser.parseFromString(htmlString, 'text/html');
                                    const bodyElement = dom.body;
                                    const nodes = $generateNodesFromDOM(editor, bodyElement);
                                    $insertNodes(nodes);
                                }
                            }
                        }
                    }
                } else {
                    // Handle HTML input - may contain markdown images inside HTML tags
                    const parser = new DOMParser();
                    const dom = parser.parseFromString(value, 'text/html');
                    const bodyElement = dom.body;

                    // Convert any markdown images inside HTML to actual img tags
                    processMarkdownImagesInHTML(bodyElement);

                    // Extract images from paragraphs to be standalone nodes
                    extractImagesFromParagraphs(bodyElement);

                    root.clear();
                    const nodes = $generateNodesFromDOM(editor, bodyElement);
                    $insertNodes(nodes);
                }
            });

            prevValueRef.current = value;
        }
    }, [value, editor, marked, isInternalUpdateRef]);

    return null;
}

function PreventAutoFocusPlugin({shouldPrevent = true}) {
    const [editor] = useLexicalComposerContext();

    useEffect(() => {
        if (!shouldPrevent) return;

        // Prevent focus on mount
        const rootElement = editor.getRootElement();
        if (!rootElement) return;

        // Remove autofocus attribute if present
        rootElement.removeAttribute('autofocus');

        // Find content editable element
        const contentEditable = rootElement.querySelector('[contenteditable="true"]');

        // Blur if currently focused
        if (document.activeElement === rootElement || rootElement.contains(document.activeElement)) {
            rootElement.blur();
            if (contentEditable && document.activeElement === contentEditable) {
                contentEditable.blur();
            }
        }

        // Prevent any focus attempts during initial render and beyond
        const preventFocus = (e) => {
            e.preventDefault();
            e.stopPropagation();
            if (document.activeElement === rootElement || rootElement.contains(document.activeElement)) {
                rootElement.blur();
                if (contentEditable) {
                    contentEditable.blur();
                }
            }
        };

        // Use capture phase to catch focus events early
        rootElement.addEventListener('focus', preventFocus, true);
        rootElement.addEventListener('focusin', preventFocus, true);

        // Also prevent focus on the content editable element directly
        if (contentEditable) {
            contentEditable.addEventListener('focus', preventFocus, true);
            contentEditable.addEventListener('focusin', preventFocus, true);
        }

        // Clean up after mount phase
        const timer = setTimeout(() => {
            rootElement.removeEventListener('focus', preventFocus, true);
            rootElement.removeEventListener('focusin', preventFocus, true);
            if (contentEditable) {
                contentEditable.removeEventListener('focus', preventFocus, true);
                contentEditable.removeEventListener('focusin', preventFocus, true);
            }
        }, 200); // Increased timeout to 200ms to ensure all initial focus attempts are caught

        return () => {
            clearTimeout(timer);
            rootElement.removeEventListener('focus', preventFocus, true);
            rootElement.removeEventListener('focusin', preventFocus, true);
            if (contentEditable) {
                contentEditable.removeEventListener('focus', preventFocus, true);
                contentEditable.removeEventListener('focusin', preventFocus, true);
            }
        };
    }, [editor, shouldPrevent]);

    return null;
}

// Main Editor Component
const LexicalEditor = forwardRef(function LexicalEditor({
                                                            value,
                                                            setValue,
                                                            placeholder = __('Enter your answer...', 'limb-chatbot'),
                                                            label,
                                                            validate,
                                                            errorMessage,
                                                            disabled = false,
                                                            className = '',
                                                            extraActions = [],
                                                            autofocus,
                                                            convertToMarkdown = true
                                                        }, ref) {
    const turndown = useMemo(() => {
        const service = new TurndownService();
        // Configure Turndown to handle images properly
        service.addRule('images', {
            filter: 'img',
            replacement: function (content, node) {
                const alt = node.alt || '';
                const src = node.src || node.getAttribute('src') || '';
                const title = node.title || '';
                if (title) {
                    return `![${alt}](${src} "${title}")`;
                }
                return `![${alt}](${src})`;
            }
        });
        return service;
    }, []);
    const insertVariableRef = useRef(null);
    const editorRef = useRef(null);
    const isInternalUpdateRef = useRef(false);
    const hasBeenTouchedRef = useRef(false);
    const isInitialLoadRef = useRef(true);

    const fieldId = useId();

    // Expose insertVariable method via ref
    useImperativeHandle(ref, () => ({
        insertVariable: (variable) => {
            if (insertVariableRef.current) {
                insertVariableRef.current.insertVariable(variable);
            }
        }
    }), []);

    // Initialize editor from HTML or markdown string
    const getInitialEditorState = () => {
        if (!value) return undefined;

        // If value is a string, convert it to editor state
        return (editor) => {
            editorRef.current = editor;

            if (typeof value === 'string' && value.trim()) {
                // Check if value looks like HTML (contains tags) or markdown
                const looksLikeHtml = /<[a-z][^>]*>[\s\S]*<\/[a-z]+>/i.test(value) ||
                    /<[a-z][^>]*\/>/i.test(value);

                if (!looksLikeHtml) {
                    // Process markdown - extract images and convert directly to ImageNodes
                    editor.update(() => {
                        const root = $getRoot();
                        root.clear();

                        // Find all image markdown patterns: ![alt](src)
                        const imageMatches = parseMarkdownImages(value);

                        if (imageMatches.length === 0) {
                            // No images, parse normally
                            const parser = new DOMParser();
                            const htmlString = marked.parse(value);
                            const dom = parser.parseFromString(htmlString, 'text/html');
                            const bodyElement = dom.body;
                            const nodes = $generateNodesFromDOM(editor, bodyElement);
                            $insertNodes(nodes);
                        } else {
                            // Process content with images
                            let lastIndex = 0;

                            imageMatches.forEach((imgMatch, index) => {
                                // Add text content before this image
                                if (imgMatch.start > lastIndex) {
                                    const textBefore = value.substring(lastIndex, imgMatch.start);
                                    if (textBefore.trim()) {
                                        const parser = new DOMParser();
                                        const htmlString = marked.parse(textBefore);
                                        const dom = parser.parseFromString(htmlString, 'text/html');
                                        const bodyElement = dom.body;
                                        const nodes = $generateNodesFromDOM(editor, bodyElement);
                                        $insertNodes(nodes);
                                    }
                                }

                                // Add the image node
                                const imageNode = $createImageNode(imgMatch.src, imgMatch.alt, '', null, null);
                                root.append(imageNode);

                                // Add a paragraph after image for proper spacing
                                const paragraph = $createParagraphNode();
                                root.append(paragraph);

                                lastIndex = imgMatch.end;
                            });

                            // Add remaining text after last image
                            if (lastIndex < value.length) {
                                const textAfter = value.substring(lastIndex);
                                if (textAfter.trim()) {
                                    const parser = new DOMParser();
                                    const htmlString = marked.parse(textAfter);
                                    const dom = parser.parseFromString(htmlString, 'text/html');
                                    const bodyElement = dom.body;
                                    const nodes = $generateNodesFromDOM(editor, bodyElement);
                                    $insertNodes(nodes);
                                }
                            }
                        }
                    });
                } else {
                    // Handle HTML input - may contain markdown images inside HTML tags
                    const parser = new DOMParser();
                    const dom = parser.parseFromString(value, 'text/html');
                    const bodyElement = dom.body;

                    // Convert any markdown images inside HTML to actual img tags
                    processMarkdownImagesInHTML(bodyElement);

                    // Extract images from paragraphs to be standalone nodes
                    extractImagesFromParagraphs(bodyElement);

                    editor.update(() => {
                        const root = $getRoot();
                        root.clear();
                        const nodes = $generateNodesFromDOM(editor, bodyElement);
                        $insertNodes(nodes);
                    });
                }
            }
        };
    };

    const initialConfig = {
        namespace: 'LexicalEditor',
        theme,
        onError: (error) => console.error(error),
        nodes: [
            HeadingNode,
            ListNode,
            ListItemNode,
            QuoteNode,
            LinkNode,
            AutoLinkNode,
            CodeNode,
            CodeHighlightNode,
            ImageNode,
            TableNode,
            TableCellNode,
            TableRowNode,
        ],
        editorState: getInitialEditorState(),
        editable: !disabled,
    };

    // Memoize onChange callback to prevent unnecessary re-renders
    const handleChange = useCallback((newValue, isUserChange = false) => {
        if (setValue) {
            // Mark as touched if this is a user-initiated change
            if (isUserChange) {
                hasBeenTouchedRef.current = true;
            }

            isInternalUpdateRef.current = true;
            setValue(newValue);

            // Only validate if field has been touched (user has interacted with it)
            if (typeof validate === 'function' && hasBeenTouchedRef.current) {
                validate(newValue);
            }

            // Don't reset the flag here - let ValueSyncPlugin reset it after processing
        }
    }, [setValue, validate]);

    return (
        <div
            className={`lbaic-settings-lexical-editor-wrapper${className ? ' ' + className : ''}${errorMessage ? ' lbaic-settings-lexical-editor-error' : ''}`}>
            {label && (
                <div className="lbaic-settings-lexical-editor-label">
                    <label htmlFor={fieldId} className='lbaic-settings-lexical-editor-label-in'>{label}</label>
                </div>
            )}
            {extraActions?.length > 0 && (
                <div className='lbaic-settings-extra-actions'>
                    {extraActions.map((item, i) => {
                        const CurrentAction = item.component;
                        const actionDisabled = item.props?.disabled !== undefined ? item.props.disabled : disabled;
                        // Create insertVariable method
                        const insertVariableMethod = (variable) => {
                            if (insertVariableRef.current) {
                                insertVariableRef.current.insertVariable(variable);
                                // Trigger validation after inserting variable
                                if (typeof validate === 'function') {
                                    // Get current value and validate after a short delay to allow editor to update
                                    setTimeout(() => {
                                        if (editorRef.current) {
                                            editorRef.current.getEditorState().read(() => {
                                                const htmlString = $generateHtmlFromNodes(editorRef.current, null);
                                                if (convertToMarkdown) {
                                                    let markdown = htmlString.trim() ? turndown.turndown(htmlString) : '';
                                                    markdown = markdown.replace(/\{([^}]*?)\}/g, (match, varContent) => {
                                                        const cleanedContent = varContent.replace(/\\_/g, '_');
                                                        return `{${cleanedContent}}`;
                                                    });
                                                    validate(markdown);
                                                } else {
                                                    validate(htmlString);
                                                }
                                            });
                                        }
                                    }, 100);
                                }
                            }
                        };
                        // Wrap chosen callback to pass insertVariable as second parameter
                        const originalChosen = item.props?.chosen;
                        const wrappedChosen = originalChosen ? (variable, insertVariable) => {
                            // Use insertVariable method if available (preserves whitespace and triggers validation)
                            if (insertVariable) {
                                insertVariableMethod(variable);
                            } else {
                                // Fallback to old method
                                originalChosen(variable, insertVariableMethod);
                            }
                        } : undefined;
                        return <CurrentAction
                            key={i}
                            {...item.props}
                            chosen={wrappedChosen}
                            insertVariable={insertVariableMethod}
                            disabled={actionDisabled}
                        />;
                    })}
                </div>
            )}
            <LexicalComposer initialConfig={initialConfig}>
                <div className="lbaic-settings-lexical-editor">
                    <ToolbarPlugin/>
                    <div className="lbaic-settings-lexical-editor-content">
                        <RichTextPlugin
                            contentEditable={
                                <ContentEditable
                                    id={fieldId}
                                    className="lbaic-settings-lexical-editor-input"
                                    contentEditable={!disabled}
                                />
                            }
                            placeholder={
                                <div className="lbaic-settings-lexical-editor-placeholder">
                                    {placeholder}
                                </div>
                            }
                            ErrorBoundary={LexicalErrorBoundary}
                        />
                        <HistoryPlugin/>
                        {(!autofocus || disabled) && <PreventAutoFocusPlugin shouldPrevent={true}/>}
                        {!disabled && autofocus && <AutoFocusPlugin/>}
                        <ListPlugin/>
                        <LinkPlugin/>
                        <TablePlugin/>
                        <InsertVariablePlugin insertVariableRef={insertVariableRef}/>
                        <ValueSyncPlugin value={value} marked={marked} isInternalUpdateRef={isInternalUpdateRef}/>
                        <OnChangePlugin
                            onChange={handleChange}
                            convertToMarkdown={convertToMarkdown}
                            turndown={turndown}
                            hasBeenTouchedRef={hasBeenTouchedRef}
                            isInitialLoadRef={isInitialLoadRef}
                        />
                    </div>
                </div>
            </LexicalComposer>
            {errorMessage && (
                <div className="lbaic-settings-lexical-editor-error-message">
                    <p className="lbaic-settings-lexical-editor-error-message-in">{errorMessage}</p>
                </div>
            )}
        </div>
    );
});

export default LexicalEditor;