"use client";
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
import { useCallback, useEffect, useRef, useState } from "react";
import { useLexicalComposerContext } from "@lexical/react/LexicalComposerContext";
import { useLexicalEditable } from "@lexical/react/useLexicalEditable";
import { $deleteTableColumnAtSelection, $deleteTableRowAtSelection, $getNodeTriplet, $getTableCellNodeFromLexicalNode, $getTableColumnIndexFromTableCellNode, $getTableNodeFromLexicalNodeOrThrow, $getTableRowIndexFromTableCellNode, $insertTableColumnAtSelection, $insertTableRowAtSelection, $isTableCellNode, $isTableRowNode, $isTableSelection, $unmergeCell, TableCellHeaderStates, TableCellNode, getTableObserverFromTableElement } from "@lexical/table";
import { $createParagraphNode, $getRoot, $getSelection, $isElementNode, $isParagraphNode, $isRangeSelection, $isTextNode } from "lexical";
import { createPortal } from "react-dom";
import use_modal from "../../hooks/use-modal.js";
import invariant from "../../shared/invariant.js";
import color_picker from "../../ui/color-picker.js";
function computeSelectionCount(selection) {
    const selectionShape = selection.getShape();
    return {
        columns: selectionShape.toX - selectionShape.fromX + 1,
        rows: selectionShape.toY - selectionShape.fromY + 1
    };
}
function isTableSelectionRectangular(selection) {
    const nodes = selection.getNodes();
    const currentRows = [];
    let currentRow = null;
    let expectedColumns = null;
    let currentColumns = 0;
    for(let i = 0; i < nodes.length; i++){
        const node = nodes[i];
        if ($isTableCellNode(node)) {
            const row = node.getParentOrThrow();
            invariant($isTableRowNode(row), 'Expected CellNode to have a RowNode parent');
            if (currentRow !== row) {
                if (null !== expectedColumns && currentColumns !== expectedColumns) return false;
                if (null !== currentRow) expectedColumns = currentColumns;
                currentRow = row;
                currentColumns = 0;
            }
            const colSpan = node.__colSpan;
            for(let j = 0; j < colSpan; j++){
                if (void 0 === currentRows[currentColumns + j]) currentRows[currentColumns + j] = 0;
                currentRows[currentColumns + j] += node.__rowSpan;
            }
            currentColumns += colSpan;
        }
    }
    return (null === expectedColumns || currentColumns === expectedColumns) && currentRows.every((v)=>v === currentRows[0]);
}
function $canUnmerge() {
    const selection = $getSelection();
    if ($isRangeSelection(selection) && !selection.isCollapsed() || $isTableSelection(selection) && !selection.anchor.is(selection.focus) || !$isRangeSelection(selection) && !$isTableSelection(selection)) return false;
    const [cell] = $getNodeTriplet(selection.anchor);
    return cell.__colSpan > 1 || cell.__rowSpan > 1;
}
function $cellContainsEmptyParagraph(cell) {
    if (1 !== cell.getChildrenSize()) return false;
    const firstChild = cell.getFirstChildOrThrow();
    if (!$isParagraphNode(firstChild) || !firstChild.isEmpty()) return false;
    return true;
}
function $selectLastDescendant(node) {
    const lastDescendant = node.getLastDescendant();
    if ($isTextNode(lastDescendant)) lastDescendant.select();
    else if ($isElementNode(lastDescendant)) lastDescendant.selectEnd();
    else if (null !== lastDescendant) lastDescendant.selectNext();
}
function currentCellBackgroundColor(editor) {
    return editor.getEditorState().read(()=>{
        const selection = $getSelection();
        if ($isRangeSelection(selection) || $isTableSelection(selection)) {
            const [cell] = $getNodeTriplet(selection.anchor);
            if ($isTableCellNode(cell)) return cell.getBackgroundColor();
        }
        return null;
    });
}
function TableActionMenu({ onClose, tableCellNode: _tableCellNode, setIsMenuOpen, contextRef, cellMerge, showColorPickerModal }) {
    const [editor] = useLexicalComposerContext();
    const dropDownRef = useRef(null);
    const [tableCellNode, updateTableCellNode] = useState(_tableCellNode);
    const [selectionCounts, updateSelectionCounts] = useState({
        columns: 1,
        rows: 1
    });
    const [canMergeCells, setCanMergeCells] = useState(false);
    const [canUnmergeCell, setCanUnmergeCell] = useState(false);
    const [backgroundColor, setBackgroundColor] = useState(()=>currentCellBackgroundColor(editor) ?? '');
    useEffect(()=>editor.registerMutationListener(TableCellNode, (nodeMutations)=>{
            const nodeUpdated = 'updated' === nodeMutations.get(tableCellNode.getKey());
            if (nodeUpdated) {
                editor.getEditorState().read(()=>{
                    updateTableCellNode(tableCellNode.getLatest());
                });
                setBackgroundColor(currentCellBackgroundColor(editor) ?? '');
            }
        }), [
        editor,
        tableCellNode
    ]);
    useEffect(()=>{
        editor.getEditorState().read(()=>{
            const selection = $getSelection();
            if ($isTableSelection(selection)) {
                const currentSelectionCounts = computeSelectionCount(selection);
                updateSelectionCounts(computeSelectionCount(selection));
                setCanMergeCells(isTableSelectionRectangular(selection) && (currentSelectionCounts.columns > 1 || currentSelectionCounts.rows > 1));
            }
            setCanUnmergeCell($canUnmerge());
        });
    }, [
        editor
    ]);
    useEffect(()=>{
        const menuButtonElement = contextRef.current;
        const dropDownElement = dropDownRef.current;
        const rootElement = editor.getRootElement();
        if (null != menuButtonElement && null != dropDownElement && null != rootElement) {
            const rootEleRect = rootElement.getBoundingClientRect();
            const menuButtonRect = menuButtonElement.getBoundingClientRect();
            dropDownElement.style.opacity = '1';
            const dropDownElementRect = dropDownElement.getBoundingClientRect();
            const margin = 5;
            let leftPosition = menuButtonRect.right + margin;
            if (leftPosition + dropDownElementRect.width > window.innerWidth || leftPosition + dropDownElementRect.width > rootEleRect.right) {
                const position = menuButtonRect.left - dropDownElementRect.width - margin;
                leftPosition = position < 0 ? margin : position;
            }
            dropDownElement.style.left = `${leftPosition}px`;
            let topPosition = menuButtonRect.top;
            if (topPosition + dropDownElementRect.height > window.innerHeight) {
                const position = menuButtonRect.bottom - dropDownElementRect.height;
                topPosition = position < 0 ? margin : position;
            }
            dropDownElement.style.top = `${topPosition}px`;
        }
    }, [
        contextRef,
        editor
    ]);
    useEffect(()=>{
        function handleClickOutside(event) {
            if (null != dropDownRef.current && null != contextRef.current && !dropDownRef.current.contains(event.target) && !contextRef.current.contains(event.target)) setIsMenuOpen(false);
        }
        window.addEventListener('click', handleClickOutside);
        return ()=>{
            window.removeEventListener('click', handleClickOutside);
        };
    }, [
        setIsMenuOpen,
        contextRef
    ]);
    const clearTableSelection = useCallback(()=>{
        editor.update(()=>{
            if (tableCellNode.isAttached()) {
                const tableNode = $getTableNodeFromLexicalNodeOrThrow(tableCellNode);
                const tableElement = editor.getElementByKey(tableNode.getKey());
                if (null == tableElement) throw new Error('Expected to find tableElement in DOM');
                const tableSelection = getTableObserverFromTableElement(tableElement);
                if (null !== tableSelection) tableSelection.$clearHighlight();
                tableNode.markDirty();
                updateTableCellNode(tableCellNode.getLatest());
            }
            const rootNode = $getRoot();
            rootNode.selectStart();
        });
    }, [
        editor,
        tableCellNode
    ]);
    const mergeTableCellsAtSelection = ()=>{
        editor.update(()=>{
            const selection = $getSelection();
            if ($isTableSelection(selection)) {
                const { columns, rows } = computeSelectionCount(selection);
                const nodes = selection.getNodes();
                let firstCell = null;
                for(let i = 0; i < nodes.length; i++){
                    const node = nodes[i];
                    if ($isTableCellNode(node)) {
                        if (null === firstCell) {
                            node.setColSpan(columns).setRowSpan(rows);
                            firstCell = node;
                            const isEmpty = $cellContainsEmptyParagraph(node);
                            let firstChild;
                            if (isEmpty && $isParagraphNode(firstChild = node.getFirstChild())) firstChild.remove();
                        } else if ($isTableCellNode(firstCell)) {
                            const isEmpty = $cellContainsEmptyParagraph(node);
                            if (!isEmpty) firstCell.append(...node.getChildren());
                            node.remove();
                        }
                    }
                }
                if (null !== firstCell) {
                    if (0 === firstCell.getChildrenSize()) firstCell.append($createParagraphNode());
                    $selectLastDescendant(firstCell);
                }
                onClose();
            }
        });
    };
    const unmergeTableCellsAtSelection = ()=>{
        editor.update(()=>{
            $unmergeCell();
        });
    };
    const insertTableRowAtSelection = useCallback((shouldInsertAfter)=>{
        editor.update(()=>{
            $insertTableRowAtSelection(shouldInsertAfter);
            onClose();
        });
    }, [
        editor,
        onClose
    ]);
    const insertTableColumnAtSelection = useCallback((shouldInsertAfter)=>{
        editor.update(()=>{
            for(let i = 0; i < selectionCounts.columns; i++)$insertTableColumnAtSelection(shouldInsertAfter);
            onClose();
        });
    }, [
        editor,
        onClose,
        selectionCounts.columns
    ]);
    const deleteTableRowAtSelection = useCallback(()=>{
        editor.update(()=>{
            $deleteTableRowAtSelection();
            onClose();
        });
    }, [
        editor,
        onClose
    ]);
    const deleteTableAtSelection = useCallback(()=>{
        editor.update(()=>{
            const tableNode = $getTableNodeFromLexicalNodeOrThrow(tableCellNode);
            tableNode.remove();
            clearTableSelection();
            onClose();
        });
    }, [
        editor,
        tableCellNode,
        clearTableSelection,
        onClose
    ]);
    const deleteTableColumnAtSelection = useCallback(()=>{
        editor.update(()=>{
            $deleteTableColumnAtSelection();
            onClose();
        });
    }, [
        editor,
        onClose
    ]);
    const toggleTableRowIsHeader = useCallback(()=>{
        editor.update(()=>{
            const tableNode = $getTableNodeFromLexicalNodeOrThrow(tableCellNode);
            const tableRowIndex = $getTableRowIndexFromTableCellNode(tableCellNode);
            const tableRows = tableNode.getChildren();
            if (tableRowIndex >= tableRows.length || tableRowIndex < 0) throw new Error('Expected table cell to be inside of table row.');
            const tableRow = tableRows[tableRowIndex];
            if (!$isTableRowNode(tableRow)) throw new Error('Expected table row');
            tableRow.getChildren().forEach((tableCell)=>{
                if (!$isTableCellNode(tableCell)) throw new Error('Expected table cell');
                tableCell.toggleHeaderStyle(TableCellHeaderStates.ROW);
            });
            clearTableSelection();
            onClose();
        });
    }, [
        editor,
        tableCellNode,
        clearTableSelection,
        onClose
    ]);
    const toggleTableColumnIsHeader = useCallback(()=>{
        editor.update(()=>{
            const tableNode = $getTableNodeFromLexicalNodeOrThrow(tableCellNode);
            const tableColumnIndex = $getTableColumnIndexFromTableCellNode(tableCellNode);
            const tableRows = tableNode.getChildren();
            const maxRowsLength = Math.max(...tableRows.map((row)=>row.getChildren().length));
            if (tableColumnIndex >= maxRowsLength || tableColumnIndex < 0) throw new Error('Expected table cell to be inside of table row.');
            for(let r = 0; r < tableRows.length; r++){
                const tableRow = tableRows[r];
                if (!$isTableRowNode(tableRow)) throw new Error('Expected table row');
                const tableCells = tableRow.getChildren();
                if (tableColumnIndex >= tableCells.length) continue;
                const tableCell = tableCells[tableColumnIndex];
                if (!$isTableCellNode(tableCell)) throw new Error('Expected table cell');
                tableCell.toggleHeaderStyle(TableCellHeaderStates.COLUMN);
            }
            clearTableSelection();
            onClose();
        });
    }, [
        editor,
        tableCellNode,
        clearTableSelection,
        onClose
    ]);
    const handleCellBackgroundColor = useCallback((value)=>{
        editor.update(()=>{
            const selection = $getSelection();
            if ($isRangeSelection(selection) || $isTableSelection(selection)) {
                const [cell] = $getNodeTriplet(selection.anchor);
                if ($isTableCellNode(cell)) cell.setBackgroundColor(value);
                if ($isTableSelection(selection)) {
                    const nodes = selection.getNodes();
                    for(let i = 0; i < nodes.length; i++){
                        const node = nodes[i];
                        if ($isTableCellNode(node)) node.setBackgroundColor(value);
                    }
                }
            }
        });
    }, [
        editor
    ]);
    let mergeCellButton = null;
    if (cellMerge) {
        if (canMergeCells) mergeCellButton = /*#__PURE__*/ jsx("button", {
            type: "button",
            className: "item",
            onClick: ()=>{
                mergeTableCellsAtSelection();
            },
            "data-test-id": "table-merge-cells",
            children: "Merge cells"
        });
        else if (canUnmergeCell) mergeCellButton = /*#__PURE__*/ jsx("button", {
            type: "button",
            className: "item",
            onClick: ()=>{
                unmergeTableCellsAtSelection();
            },
            "data-test-id": "table-unmerge-cells",
            children: "Unmerge cells"
        });
    }
    return /*#__PURE__*/ createPortal(/*#__PURE__*/ jsxs("div", {
        className: "dropdown",
        ref: dropDownRef,
        onClick: (e)=>{
            e.stopPropagation();
        },
        children: [
            mergeCellButton,
            /*#__PURE__*/ jsx("button", {
                type: "button",
                className: "item",
                onClick: ()=>{
                    showColorPickerModal('Cell background color', ()=>/*#__PURE__*/ jsx(color_picker, {
                            color: backgroundColor,
                            onChange: handleCellBackgroundColor
                        }));
                },
                "data-test-id": "table-background-color",
                children: /*#__PURE__*/ jsx("span", {
                    className: "text",
                    children: "Background color"
                })
            }),
            /*#__PURE__*/ jsx("hr", {}),
            /*#__PURE__*/ jsx("button", {
                type: "button",
                className: "item",
                onClick: ()=>{
                    insertTableRowAtSelection(false);
                },
                "data-test-id": "table-insert-row-above",
                children: /*#__PURE__*/ jsxs("span", {
                    className: "text",
                    children: [
                        "Insert ",
                        1 === selectionCounts.rows ? 'row' : `${selectionCounts.rows} rows`,
                        " above"
                    ]
                })
            }),
            /*#__PURE__*/ jsx("button", {
                type: "button",
                className: "item",
                onClick: ()=>{
                    insertTableRowAtSelection(true);
                },
                "data-test-id": "table-insert-row-below",
                children: /*#__PURE__*/ jsxs("span", {
                    className: "text",
                    children: [
                        "Insert ",
                        1 === selectionCounts.rows ? 'row' : `${selectionCounts.rows} rows`,
                        " below"
                    ]
                })
            }),
            /*#__PURE__*/ jsx("hr", {}),
            /*#__PURE__*/ jsx("button", {
                type: "button",
                className: "item",
                onClick: ()=>{
                    insertTableColumnAtSelection(false);
                },
                "data-test-id": "table-insert-column-before",
                children: /*#__PURE__*/ jsxs("span", {
                    className: "text",
                    children: [
                        "Insert ",
                        1 === selectionCounts.columns ? 'column' : `${selectionCounts.columns} columns`,
                        ' ',
                        "left"
                    ]
                })
            }),
            /*#__PURE__*/ jsx("button", {
                type: "button",
                className: "item",
                onClick: ()=>{
                    insertTableColumnAtSelection(true);
                },
                "data-test-id": "table-insert-column-after",
                children: /*#__PURE__*/ jsxs("span", {
                    className: "text",
                    children: [
                        "Insert ",
                        1 === selectionCounts.columns ? 'column' : `${selectionCounts.columns} columns`,
                        ' ',
                        "right"
                    ]
                })
            }),
            /*#__PURE__*/ jsx("hr", {}),
            /*#__PURE__*/ jsx("button", {
                type: "button",
                className: "item",
                onClick: ()=>{
                    deleteTableColumnAtSelection();
                },
                "data-test-id": "table-delete-columns",
                children: /*#__PURE__*/ jsx("span", {
                    className: "text",
                    children: "Delete column"
                })
            }),
            /*#__PURE__*/ jsx("button", {
                type: "button",
                className: "item",
                onClick: ()=>{
                    deleteTableRowAtSelection();
                },
                "data-test-id": "table-delete-rows",
                children: /*#__PURE__*/ jsx("span", {
                    className: "text",
                    children: "Delete row"
                })
            }),
            /*#__PURE__*/ jsx("button", {
                type: "button",
                className: "item",
                onClick: ()=>{
                    deleteTableAtSelection();
                },
                "data-test-id": "table-delete",
                children: /*#__PURE__*/ jsx("span", {
                    className: "text",
                    children: "Delete table"
                })
            }),
            /*#__PURE__*/ jsx("hr", {}),
            /*#__PURE__*/ jsx("button", {
                type: "button",
                className: "item",
                onClick: ()=>{
                    toggleTableRowIsHeader();
                },
                children: /*#__PURE__*/ jsxs("span", {
                    className: "text",
                    children: [
                        (tableCellNode.__headerState & TableCellHeaderStates.ROW) === TableCellHeaderStates.ROW ? 'Remove' : 'Add',
                        ' ',
                        "row header"
                    ]
                })
            }),
            /*#__PURE__*/ jsx("button", {
                type: "button",
                className: "item",
                onClick: ()=>{
                    toggleTableColumnIsHeader();
                },
                "data-test-id": "table-column-header",
                children: /*#__PURE__*/ jsxs("span", {
                    className: "text",
                    children: [
                        (tableCellNode.__headerState & TableCellHeaderStates.COLUMN) === TableCellHeaderStates.COLUMN ? 'Remove' : 'Add',
                        ' ',
                        "column header"
                    ]
                })
            })
        ]
    }), document.body);
}
function TableCellActionMenuContainer({ anchorElem, cellMerge }) {
    const [editor] = useLexicalComposerContext();
    const menuButtonRef = useRef(null);
    const menuRootRef = useRef(null);
    const [isMenuOpen, setIsMenuOpen] = useState(false);
    const [tableCellNode, setTableMenuCellNode] = useState(null);
    const [colorPickerModal, showColorPickerModal] = use_modal();
    const moveMenu = useCallback(()=>{
        const menu = menuButtonRef.current;
        const selection = $getSelection();
        const nativeSelection = window.getSelection();
        const activeElement = document.activeElement;
        if (null == selection || null == menu) return void setTableMenuCellNode(null);
        const rootElement = editor.getRootElement();
        if ($isRangeSelection(selection) && null !== rootElement && null !== nativeSelection && rootElement.contains(nativeSelection.anchorNode)) {
            const tableCellNodeFromSelection = $getTableCellNodeFromLexicalNode(selection.anchor.getNode());
            if (null == tableCellNodeFromSelection) return void setTableMenuCellNode(null);
            const tableCellParentNodeDOM = editor.getElementByKey(tableCellNodeFromSelection.getKey());
            if (null == tableCellParentNodeDOM) return void setTableMenuCellNode(null);
            setTableMenuCellNode(tableCellNodeFromSelection);
        } else if (null == activeElement) setTableMenuCellNode(null);
    }, [
        editor
    ]);
    useEffect(()=>editor.registerUpdateListener(()=>{
            editor.getEditorState().read(()=>{
                moveMenu();
            });
        }));
    useEffect(()=>{
        const menuButtonDOM = menuButtonRef.current;
        if (null != menuButtonDOM && null != tableCellNode) {
            const tableCellNodeDOM = editor.getElementByKey(tableCellNode.getKey());
            if (null != tableCellNodeDOM) {
                const tableCellRect = tableCellNodeDOM.getBoundingClientRect();
                const menuRect = menuButtonDOM.getBoundingClientRect();
                const anchorRect = anchorElem.getBoundingClientRect();
                const top = tableCellRect.top - anchorRect.top + 4;
                const left = tableCellRect.right - menuRect.width - 10 - anchorRect.left;
                menuButtonDOM.style.opacity = '1';
                menuButtonDOM.style.transform = `translate(${left}px, ${top}px)`;
            } else {
                menuButtonDOM.style.opacity = '0';
                menuButtonDOM.style.transform = 'translate(-10000px, -10000px)';
            }
        }
    }, [
        tableCellNode,
        editor,
        anchorElem
    ]);
    const prevTableCellDOM = useRef(tableCellNode);
    useEffect(()=>{
        if (prevTableCellDOM.current !== tableCellNode) setIsMenuOpen(false);
        prevTableCellDOM.current = tableCellNode;
    }, [
        tableCellNode
    ]);
    return /*#__PURE__*/ jsx("div", {
        className: "table-cell-action-button-container",
        ref: menuButtonRef,
        children: null != tableCellNode && /*#__PURE__*/ jsxs(Fragment, {
            children: [
                /*#__PURE__*/ jsx("button", {
                    type: "button",
                    className: "table-cell-action-button chevron-down",
                    onClick: (e)=>{
                        e.stopPropagation();
                        setIsMenuOpen(!isMenuOpen);
                    },
                    ref: menuRootRef,
                    children: /*#__PURE__*/ jsx("i", {
                        className: "chevron-down"
                    })
                }),
                colorPickerModal,
                isMenuOpen && /*#__PURE__*/ jsx(TableActionMenu, {
                    contextRef: menuRootRef,
                    setIsMenuOpen: setIsMenuOpen,
                    onClose: ()=>{
                        setIsMenuOpen(false);
                    },
                    tableCellNode: tableCellNode,
                    cellMerge: cellMerge,
                    showColorPickerModal: showColorPickerModal
                })
            ]
        })
    });
}
function TableActionMenuPlugin({ anchorElem = document.body, cellMerge = false }) {
    const isEditable = useLexicalEditable();
    return /*#__PURE__*/ createPortal(isEditable ? /*#__PURE__*/ jsx(TableCellActionMenuContainer, {
        anchorElem: anchorElem,
        cellMerge: cellMerge
    }) : null, anchorElem);
}
export { TableActionMenuPlugin };
