var __spreadArray = (this && this.__spreadArray) || function (to, from, pack) {
    if (pack || arguments.length === 2) for (var i = 0, l = from.length, ar; i < l; i++) {
        if (ar || !(i in from)) {
            if (!ar) ar = Array.prototype.slice.call(from, 0, i);
            ar[i] = from[i];
        }
    }
    return to.concat(ar || Array.prototype.slice.call(from));
};
import React, { useCallback, useEffect, useRef, useMemo } from 'react';
import { VariableSizeList as List } from 'react-window';
import ReactResizeDetector from 'react-resize-detector';
import { useScrollToFocusItem } from './useScrollToFocusItem';
import { isTitleListItem } from './helpers';
import { useStyles } from './styles';
var OVERSCAN_COUNT = 5;
export var VirtualGroupedList = function (_a) {
    var items = _a.items, getItemSize = _a.getItemSize, renderItem = _a.renderItem, renderGroupTitle = _a.renderGroupTitle, _b = _a.width, width = _b === void 0 ? '100%' : _b, height = _a.height, _c = _a.fixedTitle, fixedTitle = _c === void 0 ? true : _c, _d = _a.itemKey, itemKey = _d === void 0 ? function (i) { return i; } : _d, disableHorizontalScrollbar = _a.disableHorizontalScrollbar, hideSubtitles = _a.hideSubtitles, _e = _a.focusIndex, focusIndex = _e === void 0 ? null : _e, onInnerContainerResize = _a.onInnerContainerResize;
    var styles = useStyles();
    var listRef = useRef(null);
    var itemsRef = useRef(null);
    var titlesRef = useRef(null);
    var itemOffsets = useRef([0]);
    var stepCalcOffset = 10;
    var stickyItemClass = 'stickyTitleItem';
    var currentTitleParams = {
        topMargin: 0,
        index: undefined
    };
    var isGroupHasSubTitles = function (groupedItems) {
        return (groupedItems || []).some(function (item) { return item.titleItemIndex !== null; });
    };
    var hasSubTitles = useMemo(function () { return !hideSubtitles || isGroupHasSubTitles(items); }, [items, hideSubtitles]);
    var calcOffsetsToIndex = useCallback(function (index) {
        var curItemsLength = itemOffsets.current.length;
        var prevItemSize = 0;
        items.slice(curItemsLength - 1, index + 1).forEach(function (listItem, i) {
            var realIndex = curItemsLength + i - 1;
            if (i > 0)
                itemOffsets.current[realIndex] = itemOffsets.current[realIndex - 1] + prevItemSize;
            prevItemSize = getItemSize(realIndex, listItem.item);
        });
    }, [getItemSize, items]);
    var getTitleByIndex = useCallback(function (index) { return items[index].titleItemIndex; }, [items]);
    var getItemByIndex = useCallback(function (index) { return items[index]; }, [items]);
    useEffect(function () {
        requestAnimationFrame(function () {
            if (listRef.current) {
                listRef.current.scrollTo(0);
            }
        });
    }, [items.length]);
    useEffect(function () {
        var calcMoveToOffset = function (items) {
            var indexItem = items.findIndex(function (listItem) { return listItem.item.moveTo; });
            if (indexItem > -1) {
                calcOffsetsToIndex(indexItem);
                var titleIndex = getTitleByIndex(indexItem);
                return {
                    offset: itemOffsets.current[indexItem],
                    titleHeight: getItemSize(titleIndex, getItemByIndex(titleIndex).item)
                };
            }
        };
        if (listRef.current) {
            listRef.current.resetAfterIndex(0);
        }
        setTitleWidth();
        var scrollToOffset = calcMoveToOffset(items);
        if (scrollToOffset && scrollToOffset.offset && listRef.current) {
            var titleHeight_1 = scrollToOffset.titleHeight;
            var offset_1 = scrollToOffset.offset - titleHeight_1;
            if (offset_1 < listRef.current.state.scrollOffset || offset_1 > listRef.current.state.scrollOffset + height) {
                requestAnimationFrame(function () {
                    if (listRef.current) {
                        listRef.current.scrollTo(offset_1 - (height - titleHeight_1) / 2);
                    }
                });
            }
        }
    }, [calcOffsetsToIndex, getItemByIndex, getItemSize, getTitleByIndex, height, itemOffsets, items, listRef]);
    var setTitleWidth = function () {
        if (titlesRef.current && itemsRef.current) {
            titlesRef.current.style.width = itemsRef.current.offsetWidth + 'px';
        }
    };
    var getNextTitleIndex = function (fromIndex) {
        return items.findIndex(function (listItem, index) { return isTitleListItem(listItem) && fromIndex < index; });
    };
    var getItemByOffset = useCallback(function (scrollOffset) {
        var result = null;
        var offset = 0;
        items.some(function (listItem, index) {
            calcOffsetsToIndex(index + stepCalcOffset);
            var nextOffset = itemOffsets.current[index + 1];
            if (scrollOffset >= offset && scrollOffset < nextOffset)
                result = {
                    index: index,
                    offset: offset,
                    listItem: listItem
                };
            offset = nextOffset;
            return result;
        });
        return result;
    }, [calcOffsetsToIndex, itemOffsets, items]);
    var setTitleTopMargin = function (topMargin) {
        if (titlesRef.current) {
            currentTitleParams.topMargin = -topMargin;
            titlesRef.current.style.top = -topMargin + 'px';
        }
    };
    var setTitleByIndex = function (index) {
        if (titlesRef.current) {
            __spreadArray([], titlesRef.current.querySelectorAll('.' + stickyItemClass), true).forEach(function (title) {
                if (title.dataset.index === index.toString()) {
                    title.style.visibility = 'visible';
                    currentTitleParams.index = index;
                }
                else
                    title.style.visibility = 'hidden';
            });
        }
    };
    var getOffsetByIndex = function (index) {
        calcOffsetsToIndex(index);
        return itemOffsets.current[index];
    };
    var onScroll = function (_a) {
        var scrollOffset = _a.scrollOffset, scrollDirection = _a.scrollDirection;
        if (!fixedTitle || !hasSubTitles)
            return;
        var topItem = getItemByOffset(scrollOffset);
        var currentTitleIndex = topItem && getTitleByIndex(topItem.index);
        if (currentTitleIndex !== null) {
            setTitleByIndex(currentTitleIndex);
        }
        setTitleWidth();
        var titleHeight = currentTitleIndex !== null && getItemSize(currentTitleIndex, getItemByIndex(currentTitleIndex).item);
        var itemAfterTitle = getItemByOffset(scrollOffset + titleHeight + currentTitleParams.topMargin);
        var topMargin = 0;
        if (itemAfterTitle) {
            switch (scrollDirection) {
                case 'forward':
                    if (itemAfterTitle.offset - scrollOffset > 0 && isTitleListItem(itemAfterTitle.listItem))
                        topMargin = titleHeight - (itemAfterTitle.offset - scrollOffset);
                    break;
                case 'backward':
                    {
                        var nextTitleIndex = currentTitleIndex > -1 && getNextTitleIndex(currentTitleIndex);
                        var nextTitleOffset = getOffsetByIndex(nextTitleIndex);
                        if (nextTitleIndex > -1 &&
                            scrollOffset < nextTitleOffset &&
                            titleHeight >= nextTitleOffset - scrollOffset)
                            topMargin = titleHeight - (nextTitleOffset - scrollOffset);
                    }
                    break;
            }
            setTitleTopMargin(topMargin);
        }
    };
    var _getItemSize = useCallback(function (index) { return getItemSize(index, getItemByIndex(index).item); }, [getItemByIndex, getItemSize]);
    var render = useCallback(function (_a) {
        var index = _a.index, style = _a.style, data = _a.data;
        var listItem = getItemByIndex(index);
        if (!listItem.item)
            return null;
        return isTitleListItem(listItem)
            ? renderGroupTitle(style, listItem.item)
            : renderItem(style, listItem.item, index, data);
    }, [getItemByIndex, renderGroupTitle, renderItem]);
    var handleOnItemsRendered = useScrollToFocusItem({ items: items, focusIndex: focusIndex, listRef: listRef }).handleOnItemsRendered;
    var renderTitles = useCallback(function () {
        var renderTitle = function (listItem) { return (React.createElement("div", { className: stickyItemClass, style: { visibility: 'hidden' }, "data-index": listItem.index, key: listItem.index }, renderGroupTitle({ height: getItemSize(listItem.index, listItem.item) }, listItem.item))); };
        return items.filter(function (listItem) { return isTitleListItem(listItem); }).map(function (listItem) { return renderTitle(listItem); });
    }, [getItemSize, items, renderGroupTitle]);
    return (React.createElement(React.Fragment, null,
        React.createElement("div", { ref: titlesRef, "data-reltio-id": "grouped-list-sticky-titles", className: styles.stickyTitlesWrapper }, fixedTitle && renderTitles()),
        onInnerContainerResize && itemsRef.current && (React.createElement(ReactResizeDetector, { handleHeight: true, onResize: onInnerContainerResize, targetRef: itemsRef })),
        React.createElement(List, { ref: listRef, itemCount: items.length, itemSize: _getItemSize, width: width, height: height, itemKey: itemKey, innerRef: itemsRef, onScroll: onScroll, style: disableHorizontalScrollbar ? { overflowX: 'hidden' } : undefined, overscanCount: OVERSCAN_COUNT, onItemsRendered: handleOnItemsRendered }, render)));
};
