import { useContext, useEffect, useMemo, useRef } from 'react';
import { ConfigContext } from '../../ConfigProvider';
import { useTheme } from '../../theme/hooks/useTheme';
import { useScrollManagement } from '../../useScrollManagement';
import { useSet } from '../../useSet';
import { useStickyButton } from '../../useStickyButton';
import { infiniteTreeListClassnames, VIRTUOSO_CONTAINER_ID, } from '../constants';
import { flattenTree, getDescendants, getInitialExpandedIds, sortCollapsed, } from './utils';
export const useLogic = ({ initialExpandedLevel, items, onRetry, errorMsg, isError, isLoading, scrollRef, isEndReached, onLoadMore, renderItem, itemSkeleton, endOfScrollMsg, noDataImgSrc, errorImgSrc, }) => {
    const { imagesMap } = useContext(ConfigContext);
    const theme = useTheme();
    const [internalExpanded, internalExpandedActions] = useSet(new Set());
    // Set из ParentId открытых недавно нод. Используется для контролирования анимации открытия.
    // ParentId удаляется из Set после завершения анимации на всех Children
    const recentlyExpandedIds = useRef(new Set());
    // Добавляет classname для анимации закрытия элемента
    const startRemoveAnimation = (nodeId) => {
        const treeItem = document.getElementById(nodeId);
        treeItem?.classList.add(infiniteTreeListClassnames.removeAnimation);
    };
    useEffect(() => {
        const next = getInitialExpandedIds(internalExpanded, items, initialExpandedLevel);
        next.forEach((item) => internalExpandedActions.add(item));
    }, [items]);
    /**
     * Дерево, преобразованное в плоский список. Такая структура необходима для полноценной виртуализации
     */
    const flatList = useMemo(() => flattenTree(items, internalExpanded), [items, internalExpanded]);
    const onToggle = ({ id: itemId }) => {
        const isExpanded = internalExpanded.has(itemId);
        if (!isExpanded) {
            recentlyExpandedIds.current.add(itemId);
            internalExpandedActions.add(itemId);
        }
        else {
            const children = sortCollapsed(getDescendants(flatList, itemId));
            children.forEach(({ meta }) => startRemoveAnimation(meta.nodeId));
            const collapseDurationMs = theme.transitions.duration.shorter;
            setTimeout(() => {
                internalExpandedActions.remove(itemId);
                children.forEach(({ id }) => internalExpandedActions.remove(id));
            }, collapseDurationMs);
        }
    };
    const contentStateProps = useMemo(() => {
        const isNoData = !items?.length;
        return {
            // Проверка на текущие элементы списка необходима для рендера loading состояния при подгрузки данных
            // вместо общего LoadingPlaceholder на всю страницу
            isLoading: isNoData && isLoading,
            isError: isNoData && isError,
            loadingTitle: 'Загрузка данных',
            errorState: {
                imgAlt: 'Что-то пошло не так',
                errorList: [errorMsg || ''],
                imgSrc: errorImgSrc ?? imagesMap.defaultErrorImgSrc,
                onRetry,
            },
        };
    }, [items, isLoading, isError, errorMsg, onRetry, imagesMap]);
    const { scrollParent, recalculateVerticalScroll, handleEndReach, isEndReachedWithScroll, } = useScrollManagement({
        scrollRef,
        isEndReached,
        onLoadMore,
        virtuosoId: VIRTUOSO_CONTAINER_ID,
    });
    const { virtuoso, isStickyButtonActive, handleRangeChanged, handleScrollToTop, } = useStickyButton(scrollRef);
    return {
        flatList,
        onToggle,
        contentStateProps,
        scrollParent,
        virtuosoProps: {
            id: VIRTUOSO_CONTAINER_ID,
            ref: virtuoso,
            rangeChanged: handleRangeChanged,
            endReached: handleEndReach,
            totalListHeightChanged: recalculateVerticalScroll,
        },
        footerProps: {
            isError,
            isLoading,
            isEndReached: isEndReachedWithScroll,
        },
        onTopButtonProps: {
            isActive: isStickyButtonActive,
            handleScrollToTop,
            scrollRef,
        },
        endOfScrollMsg,
        itemSkeleton,
        renderItem,
        items,
        onLoadMore,
        onRetry,
        noDataImgSrc,
        recentlyExpandedIds,
    };
};
