import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
/* eslint-disable max-lines */
import { useCallback, useEffect, useLayoutEffect, useMemo, useRef, useState, forwardRef, } from 'react';
import './TableTreeFn.scss';
import TableBody from './Components/TableBody';
import TableHead from './Components/TableHead';
import { debounce } from '../../utils/debounce/debounce';
import { checkEmpty } from '../../utils/checkEmpty/checkEmpty';
const DEFAULT_COLUMN_WIDTH = 400;
const ROW_HEIGHT = 32;
const OVERSCAN = 6;
const ROOT_PARENT_ID = '__root__';
const insertNewNode = (treeData, newNode, rootNode) => {
    if (!newNode?.sourceId || !newNode.action)
        return treeData;
    const { sourceId, action, value = '', error = '', label, type, options, selectedOption, confirmIconTooltip, cancelIconTooltip, payloadSourceId, } = newNode;
    const fallbackParentId = newNode
        ?.parentId;
    const fallbackHierarchy = newNode
        ?.hierarchy;
    const convertedOptions = options?.map((option) => ({
        label: option,
        value: option,
    }));
    const convertedSelectedOption = selectedOption
        ? { label: selectedOption, value: selectedOption }
        : undefined;
    const nodeMap = new Map();
    treeData.forEach((node) => nodeMap.set(node.key, node));
    if (rootNode) {
        nodeMap.set(rootNode.key, rootNode);
    }
    const sourceNode = nodeMap.get(sourceId);
    let payloadSourceNode;
    if (payloadSourceId) {
        payloadSourceNode = nodeMap.get(payloadSourceId);
    }
    // For add-inside flows, backend can return navigateTo as a parent key or a
    // key not present in the current page. Fallback to payload source when possible.
    let effectiveSourceNode = sourceNode ?? (action === 'addInside' ? payloadSourceNode : undefined);
    if (!effectiveSourceNode && action === 'addInside' && fallbackParentId) {
        effectiveSourceNode = nodeMap.get(fallbackParentId);
    }
    const fallbackInsertAtEnd = action === 'addInside' && !effectiveSourceNode && treeData.length >= 0;
    if (!effectiveSourceNode && !fallbackInsertAtEnd)
        return treeData;
    const updatedTreeData = [...treeData];
    const sourceIndex = effectiveSourceNode
        ? treeData.findIndex((node) => node.key === effectiveSourceNode.key)
        : -1;
    let newNodeParentId = null;
    let newNodeHierarchy = 0;
    let insertionIndex = sourceIndex + 1;
    switch (action) {
        case 'addAbove': {
            const sourceNodeForInsert = effectiveSourceNode;
            if (!sourceNodeForInsert)
                return treeData;
            newNodeParentId = sourceNodeForInsert.parentId;
            newNodeHierarchy = sourceNodeForInsert.hierarchy;
            break;
        }
        case 'addBelow': {
            const sourceNodeForInsert = effectiveSourceNode;
            if (!sourceNodeForInsert)
                return treeData;
            newNodeParentId =
                payloadSourceNode?.parentId ?? sourceNodeForInsert.parentId;
            newNodeHierarchy =
                payloadSourceNode?.hierarchy ?? sourceNodeForInsert.hierarchy;
            break;
        }
        case 'addInside': {
            if (fallbackInsertAtEnd) {
                newNodeParentId =
                    fallbackParentId ?? payloadSourceId ?? sourceId ?? null;
                newNodeHierarchy = fallbackHierarchy ?? 1;
                insertionIndex = updatedTreeData.length;
                break;
            }
            const parentNode = payloadSourceNode ?? effectiveSourceNode;
            if (!parentNode)
                return treeData;
            newNodeParentId = parentNode.key;
            newNodeHierarchy = (parentNode.hierarchy ?? 0) + 1;
            // Keep add-inside input at the end of the current parent subtree.
            const parentIndex = updatedTreeData.findIndex((node) => node.key === sourceId);
            if (parentIndex !== -1) {
                insertionIndex = parentIndex + 1;
            }
            break;
        }
    }
    const newNodeBase = {
        hierarchy: newNodeHierarchy,
        parentId: newNodeParentId,
        sourceId: effectiveSourceNode?.key ?? sourceId ?? payloadSourceId ?? 'new-node',
        isNewNode: true,
        key: 'new-node',
        value,
        error,
        label,
        type,
        options: convertedOptions,
        selectedOption: convertedSelectedOption,
        confirmIconTooltip,
        cancelIconTooltip,
    };
    switch (action) {
        case 'addAbove':
            updatedTreeData.splice(sourceIndex, 0, newNodeBase);
            break;
        case 'addBelow':
            updatedTreeData.splice(sourceIndex + 1, 0, newNodeBase);
            break;
        case 'addInside':
            updatedTreeData.splice(Math.max(0, insertionIndex), 0, newNodeBase);
            break;
    }
    return updatedTreeData;
};
const prepareTreeRows = (treeData, rootNode) => {
    if (!treeData?.length)
        return [];
    const nodeById = new Map();
    const childrenByParent = new Map();
    const siblingIndex = new Map();
    const loadedCountsByParent = new Map();
    if (rootNode && rootNode.key) {
        nodeById.set(rootNode.key, rootNode);
    }
    treeData.forEach((node) => {
        nodeById.set(node.key, node);
        const parentKey = node.parentId ?? ROOT_PARENT_ID;
        if (!childrenByParent.has(parentKey)) {
            childrenByParent.set(parentKey, []);
            loadedCountsByParent.set(parentKey, { container: 0, resource: 0 });
        }
        childrenByParent.get(parentKey)?.push(node);
        const counts = loadedCountsByParent.get(parentKey);
        if (counts) {
            if (node.container) {
                counts.container++;
            }
            else {
                counts.resource++;
            }
        }
    });
    childrenByParent.forEach((children) => {
        children.forEach((child, index) => {
            siblingIndex.set(child.key, index);
        });
    });
    const hasNextSibling = (node) => {
        const parentKey = node.parentId ?? ROOT_PARENT_ID;
        const siblings = childrenByParent.get(parentKey);
        if (!siblings || siblings.length === 0)
            return false;
        const index = siblingIndex.get(node.key) ?? 0;
        if (index < siblings.length - 1)
            return true;
        const parent = nodeById.get(parentKey);
        const loadedCounts = loadedCountsByParent.get(parentKey);
        if (parent && loadedCounts) {
            const siblingContainerResources = siblings
                .filter((node) => node.container)
                .reduce((sum, node) => sum + (node.totalResourceCount ?? 0), 0);
            const siblingDirectResourcesCount = siblings.filter((node) => !node.container).length;
            const calculatedDirectResources = Math.max(0, (parent.totalResourceCount ?? 0) -
                (siblingContainerResources + siblingDirectResourcesCount));
            if (node.container) {
                const hasMoreContainers = loadedCounts.container < (parent.subContainerCount ?? 0);
                const hasResourcesFollowing = calculatedDirectResources > 0;
                return hasMoreContainers || hasResourcesFollowing;
            }
            else {
                return loadedCounts.resource < calculatedDirectResources;
            }
        }
        return false;
    };
    const buildParentSiblings = (node) => {
        const hierarchy = node.hierarchy ?? 0;
        if (hierarchy <= 0)
            return [];
        const path = [];
        let current = node;
        while (current) {
            path.unshift(current);
            if (!current.parentId)
                break;
            const parent = nodeById.get(current.parentId);
            if (!parent)
                break;
            current = parent;
        }
        const flags = path.map((ancestor) => hasNextSibling(ancestor));
        if (flags.length === hierarchy)
            return flags;
        if (flags.length > hierarchy)
            return flags.slice(flags.length - hierarchy);
        const padding = new Array(hierarchy - flags.length).fill(false);
        return padding.concat(flags);
    };
    const resolveSelectedStatus = (node) => {
        if (node.selectedStatus !== undefined)
            return node.selectedStatus;
        let current = node;
        while (current?.parentId) {
            const parent = nodeById.get(current.parentId);
            if (!parent)
                break;
            if (parent.selectedStatus === 'completely')
                return 'completely';
            if (parent.selectedStatus === 'none')
                return 'none';
            current = parent;
        }
        if (rootNode?.selectedStatus === 'completely')
            return 'completely';
        if (rootNode?.selectedStatus === 'none')
            return 'none';
        return node.selectedStatus;
    };
    return treeData.map((node) => {
        const nodeWithSiblings = node;
        const finalParentSiblings = nodeWithSiblings.parentSiblings &&
            nodeWithSiblings.parentSiblings.length > 0
            ? nodeWithSiblings.parentSiblings
            : buildParentSiblings(node);
        return {
            ...node,
            lastChild: !hasNextSibling(node),
            parentSiblings: finalParentSiblings,
            selectedStatus: resolveSelectedStatus(node),
        };
    });
};
const TableTreeFn = forwardRef(({ treeData, columnsData, selected = [], select = null, onChange = () => { }, onClick = () => { }, onExpand = () => { }, loadMore = () => { }, tableBorder, height = 'calc(100vh - 134px)', newNode, onAddConfirm = () => { }, onAddCancel = () => { }, handleEditFieldError, loading = false, rootNode, pagination = true, selectedNode, tableHeaderBgColor = 'var(--border-color)', hideOnDisable = false, freezeColumns, addModuleInputWidth = 150, addModuleSelectWidth, onScroll, onScrollEnd, disableEditLabelConfirmIcon = false, transparentHeader = false, navigateTreeNode = null, handleRemoveNavigateTreeNode = () => { }, scrollThreshold = 128, showHeader = true, resetScroll = false, setResetScroll = () => { }, }, ref) => {
    const [expanding, setExpanding] = useState(null);
    const [scrollDirection, setScrollDirection] = useState(null);
    const [virtualRange, setVirtualRange] = useState({ start: 0, end: 20 });
    const [newNodeEditable, setNewNodeEditable] = useState(false);
    const containerRef = useRef(null);
    const headerRef = useRef(null);
    const headerHeightRef = useRef(0);
    const loadingRef = useRef(loading);
    const scrollDirectionRef = useRef(null);
    const scrollRafRef = useRef(null);
    const scrollPositionRef = useRef({ lastScrollTop: 0 });
    const prevVisibleRowsRef = useRef([]);
    const suppressScrollCancelUntilRef = useRef(0);
    const debouncedScrollEndRef = useRef(null);
    const expandTargetRef = useRef(null);
    const expandingFallbackTimerRef = useRef(null);
    const navigateAttemptsRef = useRef({ key: null, attempts: 0 });
    const navigateClearTimerRef = useRef(null);
    const getWidthInfo = (width, defaultWidth) => {
        const w = width ?? defaultWidth;
        const str = String(w);
        if (str.endsWith('%')) {
            return { value: parseFloat(str), unit: '%' };
        }
        return { value: parseFloat(str) || 0, unit: 'px' };
    };
    const columnMeta = useMemo(() => {
        let stickyLeftPx = 0;
        let stickyLeftPct = 0;
        return columnsData.map((col, index) => {
            const { value, unit } = getWidthInfo(col.width, DEFAULT_COLUMN_WIDTH);
            const sticky = !!freezeColumns && index < freezeColumns;
            const widthCss = unit === '%' ? `${value}%` : `${value}px`;
            const leftCss = `calc(${stickyLeftPx}px + ${stickyLeftPct}%)`;
            const meta = {
                width: widthCss,
                sticky,
                left: leftCss,
                zIndex: sticky ? 100 + (freezeColumns ?? 0) - index : 1,
            };
            if (sticky) {
                if (unit === '%') {
                    stickyLeftPct += value;
                }
                else {
                    stickyLeftPx += value;
                }
            }
            return meta;
        });
    }, [columnsData, freezeColumns]);
    const totalWidth = useMemo(() => {
        let totalPx = 0;
        let totalPct = 0;
        columnsData.forEach((col) => {
            const { value, unit } = getWidthInfo(col.width, DEFAULT_COLUMN_WIDTH);
            if (unit === '%') {
                totalPct += value;
            }
            else {
                totalPx += value;
            }
        });
        return `calc(${totalPx}px + ${totalPct}%)`;
    }, [columnsData]);
    const frozenColumnWidth = useMemo(() => {
        if (!freezeColumns)
            return '0px';
        let totalPx = 0;
        let totalPct = 0;
        const frozenCols = columnMeta.slice(0, freezeColumns);
        frozenCols.forEach((col) => {
            const val = parseFloat(col.width) || 0;
            if (col.width.endsWith('%')) {
                totalPct += val;
            }
            else {
                totalPx += val;
            }
        });
        return `calc(${totalPx}px + ${totalPct}%)`;
    }, [columnMeta, freezeColumns]);
    const treeDataWithNewNode = useMemo(() => insertNewNode(treeData, newNode, rootNode?.node), [treeData, newNode, rootNode]);
    const preparedRows = useMemo(() => prepareTreeRows(treeDataWithNewNode, rootNode?.node), [treeDataWithNewNode, rootNode?.node]);
    const visiblePreparedRows = useMemo(() => preparedRows.filter((node) => !node.hide), [preparedRows]);
    const preparedRowsByKey = useMemo(() => {
        const map = new Map();
        preparedRows.forEach((node) => map.set(node.key, node));
        return map;
    }, [preparedRows]);
    const keyIndexMap = useMemo(() => {
        const map = new Map();
        visiblePreparedRows.forEach((node, index) => map.set(node.key, index));
        return map;
    }, [visiblePreparedRows]);
    const clearExpanding = useCallback((targetKey) => {
        setExpanding((current) => {
            if (!current)
                return current;
            if (targetKey && current !== targetKey)
                return current;
            return null;
        });
        if (!targetKey || expandTargetRef.current?.key === targetKey) {
            expandTargetRef.current = null;
        }
        if (expandingFallbackTimerRef.current) {
            clearTimeout(expandingFallbackTimerRef.current);
            expandingFallbackTimerRef.current = null;
        }
    }, []);
    useEffect(() => {
        loadingRef.current = loading;
    }, [loading]);
    useEffect(() => {
        scrollDirectionRef.current = scrollDirection;
    }, [scrollDirection]);
    const updateScrollDirection = useCallback((direction) => {
        scrollDirectionRef.current = direction;
        setScrollDirection(direction);
    }, []);
    const updateVirtualRange = useCallback(() => {
        const container = containerRef.current;
        if (!container)
            return;
        const headerHeight = headerHeightRef.current || 0;
        const rowScrollTop = Math.max(0, container.scrollTop - headerHeight);
        const viewportHeight = container.clientHeight - headerHeight;
        let start = Math.floor(rowScrollTop / ROW_HEIGHT) - OVERSCAN;
        let end = Math.ceil((rowScrollTop + viewportHeight) / ROW_HEIGHT) + OVERSCAN;
        start = Math.max(0, start);
        end = Math.min(visiblePreparedRows.length, end);
        setVirtualRange((prev) => {
            if (prev.start === start && prev.end === end)
                return prev;
            return { start, end };
        });
    }, [visiblePreparedRows.length]);
    const scheduleRangeUpdate = useCallback(() => {
        if (scrollRafRef.current !== null)
            return;
        scrollRafRef.current = requestAnimationFrame(() => {
            scrollRafRef.current = null;
            updateVirtualRange();
        });
    }, [updateVirtualRange]);
    const handleScroll = useCallback(() => {
        const container = containerRef.current;
        if (!container)
            return;
        const currentScrollTop = container.scrollTop;
        const direction = currentScrollTop > scrollPositionRef.current.lastScrollTop
            ? 'down'
            : 'up';
        scrollPositionRef.current.lastScrollTop = currentScrollTop;
        scheduleRangeUpdate();
        onScroll?.();
        debouncedScrollEndRef.current?.();
        if (!pagination ||
            loading ||
            scrollDirectionRef.current ||
            checkEmpty(treeData))
            return;
        const scrollHeight = container.scrollHeight;
        const clientHeight = container.clientHeight;
        const nearBottom = scrollHeight - (currentScrollTop + clientHeight) < scrollThreshold;
        if (direction === 'down' &&
            nearBottom &&
            !treeData[treeData.length - 1]?.lastResource) {
            updateScrollDirection('below');
            loadMore('below');
        }
    }, [
        treeData,
        pagination,
        loading,
        scrollDirection,
        scrollThreshold,
        scheduleRangeUpdate,
        onScroll,
        loadMore,
        updateScrollDirection,
    ]);
    useEffect(() => {
        if (loading || !pagination || checkEmpty(treeData))
            return;
        const firstNode = treeData[0];
        const hasMoreAbove = !firstNode?.lastResource;
        const { totalSubContainerCount = 0, totalResourceCount = 0 } = rootNode?.node || {};
        const totalItems = totalSubContainerCount + totalResourceCount;
        const isListTooShort = visiblePreparedRows.length < 10 &&
            visiblePreparedRows.length < totalItems;
        if (hasMoreAbove && isListTooShort) {
            updateScrollDirection('above');
            loadMore('above');
        }
    }, [
        loading,
        pagination,
        treeData,
        visiblePreparedRows.length,
        rootNode,
        loadMore,
        updateScrollDirection,
    ]);
    useLayoutEffect(() => {
        const oldRows = prevVisibleRowsRef.current;
        const newRows = visiblePreparedRows;
        const container = containerRef.current;
        if (resetScroll && container) {
            container.scrollTop = 0;
            scrollPositionRef.current.lastScrollTop = 0;
            setResetScroll(false);
            return;
        }
        else if (container && oldRows.length > 0 && newRows.length > 0) {
            if (!loading) {
                const lastScrollTop = scrollPositionRef.current.lastScrollTop;
                const topVisibleIndex = Math.max(0, Math.floor(lastScrollTop / ROW_HEIGHT));
                let oldIndex = -1;
                let newIndex = -1;
                for (let i = topVisibleIndex; i < oldRows.length; i++) {
                    const key = oldRows[i]?.key;
                    const foundNewIndex = keyIndexMap.get(key ?? '');
                    if (foundNewIndex !== undefined) {
                        oldIndex = i;
                        newIndex = foundNewIndex;
                        break;
                    }
                }
                if (oldIndex === -1) {
                    for (let i = topVisibleIndex - 1; i >= 0; i--) {
                        const key = oldRows[i]?.key;
                        const foundNewIndex = keyIndexMap.get(key ?? '');
                        if (foundNewIndex !== undefined) {
                            oldIndex = i;
                            newIndex = foundNewIndex;
                            break;
                        }
                    }
                }
                if (oldIndex !== -1 && newIndex !== -1) {
                    const deltaRows = newIndex - oldIndex;
                    const targetScrollTop = Math.max(0, lastScrollTop + deltaRows * ROW_HEIGHT);
                    if (container.scrollTop !== targetScrollTop) {
                        container.scrollTop = targetScrollTop;
                        scrollPositionRef.current.lastScrollTop = container.scrollTop;
                        updateVirtualRange();
                    }
                }
                else {
                    // FIX: Graceful Fallback
                    if (scrollDirection === 'above') {
                        // Only push to 0 if they specifically requested data ABOVE them
                        if (container.scrollTop !== 0) {
                            container.scrollTop = 0;
                            scrollPositionRef.current.lastScrollTop = 0;
                            updateVirtualRange();
                        }
                    }
                    else {
                        // For all other cases (canceling an add, shrinking), just safely clamp the scroll
                        // so it doesn't point to empty space, but DO NOT force it to 0.
                        const headerHeight = headerHeightRef.current || 0;
                        const maxScrollTop = Math.max(0, newRows.length * ROW_HEIGHT -
                            (container.clientHeight - headerHeight));
                        if (container.scrollTop > maxScrollTop) {
                            container.scrollTop = maxScrollTop;
                            scrollPositionRef.current.lastScrollTop = maxScrollTop;
                            updateVirtualRange();
                        }
                    }
                }
                if (scrollDirection) {
                    updateScrollDirection(null);
                }
            }
        }
        prevVisibleRowsRef.current = newRows;
    }, [
        loading,
        scrollDirection,
        keyIndexMap,
        visiblePreparedRows,
        updateScrollDirection,
        updateVirtualRange,
        resetScroll,
        setResetScroll,
    ]);
    useEffect(() => {
        const container = containerRef.current;
        if (!container)
            return;
        const handleWheelAtTop = (event) => {
            if (event.deltaY >= 0)
                return;
            if (!pagination || checkEmpty(treeData) || loadingRef.current)
                return;
            if (scrollDirectionRef.current)
                return;
            if (container.scrollTop > 1 || treeData[0]?.lastResource)
                return;
            updateScrollDirection('above');
            loadMore('above');
        };
        container.addEventListener('wheel', handleWheelAtTop, { passive: true });
        return () => {
            container.removeEventListener('wheel', handleWheelAtTop);
        };
    }, [pagination, treeData, loadMore, updateScrollDirection]);
    useEffect(() => {
        const container = containerRef.current;
        if (!container)
            return;
        debouncedScrollEndRef.current = onScrollEnd
            ? debounce(() => {
                onScrollEnd?.();
            }, 150)
            : null;
        container.addEventListener('scroll', handleScroll, { passive: true });
        return () => {
            container.removeEventListener('scroll', handleScroll);
            debouncedScrollEndRef.current?.cancel();
        };
    }, [handleScroll, onScrollEnd]);
    useEffect(() => {
        const container = containerRef.current;
        if (!container)
            return;
        const handleScrollCapture = (event) => {
            if (Date.now() < suppressScrollCancelUntilRef.current) {
                event.stopImmediatePropagation();
            }
        };
        container.addEventListener('scroll', handleScrollCapture, {
            passive: true,
            capture: true,
        });
        return () => {
            container.removeEventListener('scroll', handleScrollCapture, true);
        };
    }, []);
    useEffect(() => {
        const headerNode = headerRef.current;
        if (!headerNode)
            return;
        const updateHeight = () => {
            headerHeightRef.current = headerNode.getBoundingClientRect().height;
            updateVirtualRange();
        };
        const resizeObserver = new ResizeObserver(updateHeight);
        resizeObserver.observe(headerNode);
        return () => resizeObserver.disconnect();
    }, [updateVirtualRange]);
    useLayoutEffect(() => {
        if (!newNode || !containerRef.current)
            return;
        const container = containerRef.current;
        const newNodeIndex = keyIndexMap.get('new-node');
        if (newNodeIndex === undefined)
            return;
        const headerHeight = headerHeightRef.current || 0;
        const viewportHeight = container.clientHeight - headerHeight;
        if (viewportHeight <= 0)
            return;
        const rowTop = newNodeIndex * ROW_HEIGHT;
        const rowBottom = rowTop + ROW_HEIGHT;
        const rowScrollTop = Math.max(0, container.scrollTop - headerHeight);
        const viewTop = rowScrollTop;
        const viewBottom = rowScrollTop + viewportHeight;
        let nextRowScrollTop = rowScrollTop;
        if (rowTop < viewTop) {
            nextRowScrollTop = rowTop;
        }
        else if (rowBottom > viewBottom) {
            nextRowScrollTop = Math.max(0, rowBottom - viewportHeight);
        }
        if (nextRowScrollTop !== rowScrollTop) {
            suppressScrollCancelUntilRef.current = Date.now() + 300;
            container.scrollTop = nextRowScrollTop + headerHeight;
            scrollPositionRef.current.lastScrollTop = container.scrollTop;
            updateVirtualRange();
        }
        const rafId = requestAnimationFrame(() => {
            setNewNodeEditable(true);
        });
        return () => cancelAnimationFrame(rafId);
    }, [newNode, keyIndexMap, updateVirtualRange]);
    useEffect(() => {
        if (!newNode) {
            setNewNodeEditable(false);
        }
    }, [newNode]);
    useLayoutEffect(() => {
        if (!expanding || loading)
            return;
        const expected = expandTargetRef.current;
        if (!expected || expected.key !== expanding) {
            const rafId = requestAnimationFrame(() => {
                clearExpanding(expanding);
            });
            return () => cancelAnimationFrame(rafId);
        }
        const updatedNode = preparedRowsByKey.get(expected.key);
        if (!updatedNode) {
            const rafId = requestAnimationFrame(() => {
                clearExpanding(expected.key);
            });
            return () => cancelAnimationFrame(rafId);
        }
        if (Boolean(updatedNode.expanded) !== expected.expanded)
            return;
        const rafId = requestAnimationFrame(() => {
            clearExpanding(expected.key);
        });
        return () => cancelAnimationFrame(rafId);
    }, [preparedRowsByKey, expanding, loading, clearExpanding]);
    useEffect(() => {
        if (navigateAttemptsRef.current.key !== navigateTreeNode) {
            navigateAttemptsRef.current = {
                key: navigateTreeNode,
                attempts: 0,
            };
        }
        if (!navigateTreeNode && navigateClearTimerRef.current) {
            clearTimeout(navigateClearTimerRef.current);
            navigateClearTimerRef.current = null;
        }
    }, [navigateTreeNode]);
    useLayoutEffect(() => {
        if (!navigateTreeNode || newNode)
            return;
        const container = containerRef.current;
        if (!container)
            return;
        const rowIndex = keyIndexMap.get(navigateTreeNode);
        if (rowIndex !== undefined) {
            navigateAttemptsRef.current = {
                key: navigateTreeNode,
                attempts: 0,
            };
            const headerHeight = headerHeightRef.current || 0;
            const viewportHeight = Math.max(ROW_HEIGHT, container.clientHeight - headerHeight);
            const rowCenter = rowIndex * ROW_HEIGHT + ROW_HEIGHT / 2;
            const targetTop = Math.max(0, rowCenter - viewportHeight / 2) + headerHeight;
            suppressScrollCancelUntilRef.current = Date.now() + 400;
            container.scrollTo({
                top: targetTop,
                behavior: 'smooth',
            });
            scheduleRangeUpdate();
            if (navigateClearTimerRef.current) {
                clearTimeout(navigateClearTimerRef.current);
            }
            navigateClearTimerRef.current = setTimeout(() => {
                handleRemoveNavigateTreeNode?.();
            }, 350);
            return;
        }
        if (loading || scrollDirection)
            return;
        const retryState = navigateAttemptsRef.current;
        if (retryState.key !== navigateTreeNode) {
            retryState.key = navigateTreeNode;
            retryState.attempts = 0;
        }
        retryState.attempts += 1;
        if (retryState.attempts > 30) {
            handleRemoveNavigateTreeNode?.();
            return;
        }
        if (pagination && treeData[0]?.lastResource !== true) {
            updateScrollDirection('above');
            loadMore('above');
            return;
        }
        if (retryState.attempts > 2) {
            handleRemoveNavigateTreeNode?.();
        }
    }, [
        navigateTreeNode,
        newNode,
        keyIndexMap,
        loading,
        scrollDirection,
        pagination,
        treeData,
        loadMore,
        scheduleRangeUpdate,
        handleRemoveNavigateTreeNode,
        updateScrollDirection,
    ]);
    const handleToggleExpand = useCallback((node) => {
        if (expanding)
            return;
        const nextExpandedState = !node?.expanded;
        setExpanding(node.key);
        expandTargetRef.current = {
            key: node.key,
            expanded: nextExpandedState,
        };
        if (expandingFallbackTimerRef.current) {
            clearTimeout(expandingFallbackTimerRef.current);
        }
        const fallbackStartedAt = Date.now();
        const MAX_FALLBACK_WAIT_MS = 2000;
        const FALLBACK_CHECK_INTERVAL_MS = 1000;
        const ensureExpandCleanup = () => {
            if (expandTargetRef.current?.key !== node.key)
                return;
            const isStillLoading = loadingRef.current;
            const didTimeout = Date.now() - fallbackStartedAt >= MAX_FALLBACK_WAIT_MS;
            if (isStillLoading && !didTimeout) {
                expandingFallbackTimerRef.current = setTimeout(ensureExpandCleanup, FALLBACK_CHECK_INTERVAL_MS);
                return;
            }
            clearExpanding(node.key);
        };
        expandingFallbackTimerRef.current = setTimeout(ensureExpandCleanup, FALLBACK_CHECK_INTERVAL_MS);
        onExpand?.(node);
    }, [expanding, onExpand, clearExpanding]);
    const handleCheckBoxChange = useCallback((e, node) => {
        if (expanding)
            return;
        onChange?.(e, node);
    }, [onChange, expanding]);
    const handleRowClick = useCallback((e, node) => {
        if (expanding)
            return;
        onClick?.(e, node);
    }, [onClick, expanding]);
    useEffect(() => {
        return () => {
            if (scrollRafRef.current !== null) {
                cancelAnimationFrame(scrollRafRef.current);
                scrollRafRef.current = null;
            }
            if (expandingFallbackTimerRef.current) {
                clearTimeout(expandingFallbackTimerRef.current);
            }
            if (navigateClearTimerRef.current) {
                clearTimeout(navigateClearTimerRef.current);
            }
        };
    }, []);
    const totalHeight = visiblePreparedRows.length * ROW_HEIGHT;
    const visibleRows = visiblePreparedRows.slice(virtualRange.start, virtualRange.end);
    return (_jsx("div", { className: "tree-table-wrapper-container table-tree-fn", children: _jsx("div", { className: "tree-table-fn-wrap", ref: ref, children: _jsx("div", { className: `table-fn-scrollable ${visiblePreparedRows.length ? '' : 'table-fn-empty'}`, ref: containerRef, style: {
                    '--table-height': visiblePreparedRows.length ? height : 'auto',
                    '--frozen-column-width': frozenColumnWidth,
                    border: tableBorder,
                }, children: _jsxs("div", { className: "tree-table-fn", style: { width: totalWidth }, children: [_jsx("div", { ref: headerRef, style: { position: 'sticky', top: 0, zIndex: 98 }, children: _jsx(TableHead, { columnsData: columnsData, columnMeta: columnMeta, totalWidth: totalWidth, rootNode: rootNode, onCheckBoxChange: handleCheckBoxChange, selected: selected, selectedNode: selectedNode, tableHeaderBgColor: tableHeaderBgColor, hideOnDisable: hideOnDisable, transparentHeader: transparentHeader, showHeader: showHeader }) }), _jsx(TableBody, { flattenedTreeData: visibleRows, columnsData: columnsData, columnMeta: columnMeta, totalWidth: totalWidth, rowHeight: ROW_HEIGHT, startIndex: virtualRange.start, totalHeight: totalHeight, selected: selected, select: select, onRowClick: handleRowClick, onToggleExpand: handleToggleExpand, onCheckBoxChange: handleCheckBoxChange, onAddConfirm: onAddConfirm, onAddCancel: onAddCancel, handleEditFieldError: handleEditFieldError, expanding: expanding, selectedNode: selectedNode, hideOnDisable: hideOnDisable, addModuleInputWidth: addModuleInputWidth, addModuleSelectWidth: addModuleSelectWidth, disableEditLabelConfirmIcon: disableEditLabelConfirmIcon, isEditable: newNode ? newNodeEditable : undefined, setIsEditable: newNode
                                ? (id) => {
                                    setNewNodeEditable(Boolean(id));
                                }
                                : undefined })] }) }) }) }));
});
TableTreeFn.displayName = 'TableTreeFn';
export default TableTreeFn;
//# sourceMappingURL=TableTreeFn.js.map