import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
import { useCallback, useRef, useState, useEffect, forwardRef, } from "react";
import { SLATE_MARKS, SLATE_BLOCKS, } from "../types";
import { SimpleToolbar } from "./SimpleToolbar";
import { cn } from "../../../../lib/utils";
import "./SimpleRichTextEditor.css";
export const SimpleRichTextEditor = forwardRef((props, ref) => {
    const { value = "", onChange, onFocus, onBlur, readOnly = false, placeholder = "Enter some text...", profile, } = props;
    const editorRef = useRef(null);
    const [state, setState] = useState({
        selection: null,
        activeFormats: new Set(),
        currentBlock: "paragraph",
        currentAlignment: "left",
    });
    const editorProfile = profile || {
        toolbar: {
            groups: [],
        },
    };
    // Update content when value prop changes (only when editor is not focused)
    useEffect(() => {
        if (editorRef.current &&
            editorRef.current.innerHTML !== value &&
            document.activeElement !== editorRef.current) {
            editorRef.current.innerHTML = value || "";
        }
    }, [value]);
    // Initialize content on mount
    useEffect(() => {
        if (editorRef.current && !editorRef.current.innerHTML && value) {
            editorRef.current.innerHTML = value;
        }
    }, []);
    // Save current selection
    const saveSelection = useCallback(() => {
        const selection = window.getSelection();
        if (selection && selection.rangeCount > 0) {
            return selection.getRangeAt(0);
        }
        return null;
    }, []);
    // Restore selection
    const restoreSelection = useCallback((range) => {
        const selection = window.getSelection();
        if (selection) {
            selection.removeAllRanges();
            selection.addRange(range);
        }
    }, []);
    // Update editor state based on current selection
    const updateEditorState = useCallback(() => {
        if (!editorRef.current)
            return;
        const selection = window.getSelection();
        if (!selection || selection.rangeCount === 0)
            return;
        const range = selection.getRangeAt(0);
        const activeFormats = new Set();
        // Check for active marks
        Object.keys(SLATE_MARKS).forEach((markId) => {
            const markConfig = SLATE_MARKS[markId];
            if (document.queryCommandState(getExecCommandForMark(markId))) {
                activeFormats.add(markId);
            }
        });
        // Check current block type
        let currentBlock = "paragraph";
        const parentElement = range.commonAncestorContainer.nodeType === Node.TEXT_NODE
            ? range.commonAncestorContainer.parentElement
            : range.commonAncestorContainer;
        if (parentElement) {
            const blockElement = parentElement.closest("h1, h2, h3, h4, h5, h6, p, div");
            if (blockElement) {
                switch (blockElement.tagName.toLowerCase()) {
                    case "h1":
                        currentBlock = "heading-1";
                        break;
                    case "h2":
                        currentBlock = "heading-2";
                        break;
                    case "h3":
                        currentBlock = "heading-3";
                        break;
                    case "h4":
                        currentBlock = "heading-4";
                        break;
                    case "h5":
                        currentBlock = "heading-5";
                        break;
                    case "h6":
                        currentBlock = "heading-6";
                        break;
                    case "p":
                        currentBlock = "paragraph";
                        break;
                    default:
                        currentBlock = "no-tag";
                        break;
                }
            }
        }
        // Check current alignment
        let currentAlignment = "left";
        const computedStyle = window.getComputedStyle(parentElement || editorRef.current);
        const textAlign = computedStyle.textAlign;
        if (["center", "right", "justify"].includes(textAlign)) {
            currentAlignment = textAlign;
        }
        setState({
            selection: range,
            activeFormats,
            currentBlock,
            currentAlignment,
        });
    }, []);
    // Get execCommand equivalent for marks
    const getExecCommandForMark = (markId) => {
        switch (markId) {
            case "bold":
                return "bold";
            case "italic":
                return "italic";
            case "underline":
                return "underline";
            case "strikethrough":
                return "strikeThrough";
            case "subscript":
                return "subscript";
            case "superscript":
                return "superscript";
            default:
                return "";
        }
    };
    // Apply mark formatting
    const toggleMark = useCallback((markId) => {
        if (readOnly)
            return;
        editorRef.current?.focus();
        const command = getExecCommandForMark(markId);
        if (command) {
            document.execCommand(command, false);
        }
        else if (markId === "extrabold") {
            // Custom handling for extrabold
            const selection = window.getSelection();
            if (selection && selection.rangeCount > 0) {
                const range = selection.getRangeAt(0);
                const selectedText = range.toString();
                if (selectedText) {
                    const span = document.createElement("span");
                    span.className = "extrabold";
                    span.textContent = selectedText;
                    range.deleteContents();
                    range.insertNode(span);
                    // Move cursor after the inserted span
                    range.setStartAfter(span);
                    range.collapse(true);
                    selection.removeAllRanges();
                    selection.addRange(range);
                }
            }
        }
        setTimeout(() => {
            updateEditorState();
            if (onChange && editorRef.current) {
                onChange(editorRef.current.innerHTML);
            }
        }, 0);
    }, [readOnly, onChange, updateEditorState]);
    // Apply block formatting
    const toggleBlock = useCallback((blockId) => {
        if (readOnly)
            return;
        editorRef.current?.focus();
        if (blockId === "no-tag") {
            document.execCommand("formatBlock", false, "div");
        }
        else {
            const blockConfig = SLATE_BLOCKS[blockId];
            if (blockConfig && blockConfig.htmlTag !== "no-tag") {
                document.execCommand("formatBlock", false, `<${blockConfig.htmlTag}>`);
            }
        }
        setTimeout(() => {
            updateEditorState();
            if (onChange && editorRef.current) {
                onChange(editorRef.current.innerHTML);
            }
        }, 0);
    }, [readOnly, onChange, updateEditorState]);
    // Apply alignment
    const toggleAlign = useCallback((alignment) => {
        if (readOnly)
            return;
        editorRef.current?.focus();
        let command = "";
        switch (alignment) {
            case "left":
                command = "justifyLeft";
                break;
            case "center":
                command = "justifyCenter";
                break;
            case "right":
                command = "justifyRight";
                break;
            case "justify":
                command = "justifyFull";
                break;
        }
        if (command) {
            document.execCommand(command, false);
        }
        setTimeout(() => {
            updateEditorState();
            if (onChange && editorRef.current) {
                onChange(editorRef.current.innerHTML);
            }
        }, 100);
    }, [readOnly, onChange, updateEditorState]);
    // Apply list formatting
    const toggleList = useCallback((listType) => {
        if (readOnly)
            return;
        editorRef.current?.focus();
        const command = listType === "unordered"
            ? "insertUnorderedList"
            : "insertOrderedList";
        document.execCommand(command, false);
        setTimeout(() => {
            updateEditorState();
            if (onChange && editorRef.current) {
                onChange(editorRef.current.innerHTML);
            }
        }, 100);
    }, [readOnly, onChange, updateEditorState]);
    // Strip formatting
    const stripFormatting = useCallback(() => {
        if (readOnly)
            return;
        editorRef.current?.focus();
        document.execCommand("removeFormat", false);
        setTimeout(() => {
            updateEditorState();
            if (onChange && editorRef.current) {
                onChange(editorRef.current.innerHTML);
            }
        }, 100);
    }, [readOnly, onChange, updateEditorState]);
    // Handle input changes
    const handleInput = useCallback(() => {
        // Don't immediately update editor state to avoid selection interference
        if (onChange && editorRef.current) {
            onChange(editorRef.current.innerHTML);
        }
        // Update state after a brief delay
        setTimeout(() => {
            updateEditorState();
        }, 50);
    }, [onChange, updateEditorState]);
    // Handle selection changes (debounced to avoid interference)
    const handleSelectionChange = useCallback(() => {
        if (document.activeElement === editorRef.current) {
            // Debounce to avoid interfering with user selection
            setTimeout(() => {
                if (document.activeElement === editorRef.current) {
                    updateEditorState();
                }
            }, 100);
        }
    }, [updateEditorState]);
    // Handle focus
    const handleFocus = useCallback(() => {
        // Delay updateEditorState to allow natural cursor positioning
        setTimeout(() => {
            updateEditorState();
        }, 50);
        if (onFocus) {
            onFocus();
        }
    }, [onFocus, updateEditorState]);
    // Handle blur
    const handleBlur = useCallback(() => {
        if (onBlur) {
            onBlur();
        }
    }, [onBlur]);
    // Handle key down for shortcuts
    const handleKeyDown = useCallback((event) => {
        if (readOnly)
            return;
        // Handle keyboard shortcuts
        if (event.ctrlKey || event.metaKey) {
            switch (event.key.toLowerCase()) {
                case "b":
                    event.preventDefault();
                    toggleMark("bold");
                    break;
                case "i":
                    event.preventDefault();
                    toggleMark("italic");
                    break;
                case "u":
                    event.preventDefault();
                    toggleMark("underline");
                    break;
            }
        }
        // Handle Enter key for lists
        if (event.key === "Enter") {
            const selection = window.getSelection();
            if (selection && selection.rangeCount > 0) {
                const range = selection.getRangeAt(0);
                const listItem = range.startContainer.nodeType === Node.TEXT_NODE
                    ? range.startContainer.parentElement?.closest("li")
                    : range.startContainer.closest("li");
                if (listItem && !listItem.textContent?.trim()) {
                    // If we're in an empty list item, break out of the list
                    event.preventDefault();
                    document.execCommand("outdent", false);
                }
            }
        }
    }, [readOnly, toggleMark]);
    // Set up selection change listener
    useEffect(() => {
        document.addEventListener("selectionchange", handleSelectionChange);
        return () => {
            document.removeEventListener("selectionchange", handleSelectionChange);
        };
    }, [handleSelectionChange]);
    // Check if a mark is active
    const isMarkActive = useCallback((markId) => {
        return state.activeFormats.has(markId);
    }, [state.activeFormats]);
    // Check if a block is active
    const isBlockActive = useCallback((blockId) => {
        return state.currentBlock === blockId;
    }, [state.currentBlock]);
    // Check if an alignment is active
    const isAlignActive = useCallback((alignment) => {
        return state.currentAlignment === alignment;
    }, [state.currentAlignment]);
    // Check if a list is active
    const isListActive = useCallback((listType) => {
        return document.queryCommandState(listType === "unordered"
            ? "insertUnorderedList"
            : "insertOrderedList");
    }, []);
    return (_jsxs("div", { className: `simple-rich-text-editor ${props.className || ""}`, children: [!readOnly && (_jsx(SimpleToolbar, { profile: editorProfile, isMarkActive: isMarkActive, isBlockActive: isBlockActive, isAlignActive: isAlignActive, isListActive: isListActive, toggleMark: toggleMark, toggleBlock: toggleBlock, toggleAlign: toggleAlign, toggleList: toggleList, stripFormatting: stripFormatting })), _jsx("div", { ref: editorRef, contentEditable: !readOnly, className: cn("simple-editor-content", readOnly ? "bg-gray-5" : "bg-gray-5", "focus-shadow p-2"), onInput: handleInput, onFocus: handleFocus, onBlur: handleBlur, onKeyDown: handleKeyDown, style: {
                    minHeight: "100px",
                    outline: "none",
                }, suppressContentEditableWarning: true, "data-placeholder": placeholder })] }));
});
SimpleRichTextEditor.displayName = "SimpleRichTextEditor";
export default SimpleRichTextEditor;
//# sourceMappingURL=SimpleRichTextEditor.js.map