import React__default, { useRef, useState, useMemo, useEffect, useImperativeHandle } from "react";
import { getItemRelativeTop, getScrollPercentage, getItemAbsoluteTop, GHOST_ITEM_KEY, getCompareItemRelativeTop, getNodeHeight, getLongestItemIndex, getRangeIndex, getValidScrollTop, getLocationItem } from "./utils/itemUtil.js";
import { caf, raf } from "../../_util/raf.js";
import { isNumber } from "../../_util/is.js";
import usePrevious from "../../_util/hooks/usePrevious.js";
import { findListDiffIndex, getIndexByStartLoc } from "./utils/algorithmUtil.js";
import Filler from "./Filler.js";
import useStateWithPromise from "../../_util/hooks/useStateWithPromise.js";
import useIsFirstRender from "../../_util/hooks/useIsFirstRender.js";
import useForceUpdate from "../../_util/hooks/useForceUpdate.js";
import ResizeObserver from "../../_util/resizeObserver.js";
import useIsomorphicLayoutEffect from "../../_util/hooks/useIsomorphicLayoutEffect.js";
import { jsx, jsxs, Fragment } from "../../../../../../../@emotion_react@11.10.4_3toe27fv7etiytxb5kxc7fxaw4/node_modules/@emotion/react/jsx-runtime/dist/emotion-react-jsx-runtime.browser.esm.js";
var __assign = globalThis && globalThis.__assign || function() {
  __assign = Object.assign || function(t) {
    for (var s, i = 1, n = arguments.length; i < n; i++) {
      s = arguments[i];
      for (var p in s)
        if (Object.prototype.hasOwnProperty.call(s, p))
          t[p] = s[p];
    }
    return t;
  };
  return __assign.apply(this, arguments);
};
var __rest = globalThis && globalThis.__rest || function(s, e) {
  var t = {};
  for (var p in s)
    if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0)
      t[p] = s[p];
  if (s != null && typeof Object.getOwnPropertySymbols === "function")
    for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) {
      if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i]))
        t[p[i]] = s[p[i]];
    }
  return t;
};
var __read = globalThis && globalThis.__read || function(o, n) {
  var m = typeof Symbol === "function" && o[Symbol.iterator];
  if (!m)
    return o;
  var i = m.call(o), r, ar = [], e;
  try {
    while ((n === void 0 || n-- > 0) && !(r = i.next()).done)
      ar.push(r.value);
  } catch (error) {
    e = {
      error
    };
  } finally {
    try {
      if (r && !r.done && (m = i["return"]))
        m.call(i);
    } finally {
      if (e)
        throw e.error;
    }
  }
  return ar;
};
var DEFAULT_VIRTUAL_ITEM_HEIGHT = 32;
var KEY_VIRTUAL_ITEM_HEIGHT = "__virtual_item_height_" + Math.random().toFixed(5).slice(2);
var useComputeVirtualItemHeight = function(refItemHeightMap) {
  var forceUpdate = useForceUpdate();
  var heightMap = refItemHeightMap.current;
  useEffect(function() {
    if (Object.keys(heightMap).length && !heightMap[KEY_VIRTUAL_ITEM_HEIGHT]) {
      heightMap[KEY_VIRTUAL_ITEM_HEIGHT] = Object.entries(heightMap).reduce(function(sum, _a, currentIndex, array) {
        var _b = __read(_a, 2), currentHeight = _b[1];
        var nextSum = sum + currentHeight;
        return currentIndex === array.length - 1 ? Math.round(nextSum / array.length) : nextSum;
      }, 0);
      forceUpdate();
    }
  }, [Object.keys(heightMap).length]);
};
var useCacheChildrenNodes = function(children) {
  var refCacheMap = useRef({});
  var refPrevChildren = useRef(children);
  useEffect(function() {
    refPrevChildren.current = children;
  }, [children]);
  if (children !== refPrevChildren.current) {
    refCacheMap.current = {};
  }
  return function(item, index, props) {
    if (!refCacheMap.current.hasOwnProperty(index)) {
      refCacheMap.current[index] = children(item, index, props);
    }
    return refCacheMap.current[index];
  };
};
var VirtualList = React__default.forwardRef(function(props, ref) {
  var style = props.style, className = props.className, children = props.children, _a = props.data, data = _a === void 0 ? [] : _a, itemKey = props.itemKey, _b = props.threshold, threshold = _b === void 0 ? 100 : _b, _c = props.wrapper, WrapperTagName = _c === void 0 ? "div" : _c, _d = props.height, propHeight = _d === void 0 ? "100%" : _d, _e = props.isStaticItemHeight, isStaticItemHeight = _e === void 0 ? true : _e, propItemHeight = props.itemHeight, measureLongestItem = props.measureLongestItem, scrollOptions = props.scrollOptions, onScroll = props.onScroll, _f = props.needFiller, needFiller = _f === void 0 ? true : _f, outerStyle = props.outerStyle, restProps = __rest(props, ["style", "className", "children", "data", "itemKey", "threshold", "wrapper", "height", "isStaticItemHeight", "itemHeight", "measureLongestItem", "scrollOptions", "onScroll", "needFiller", "outerStyle"]);
  var styleListMaxHeight = style && style.maxHeight || propHeight;
  var refItemHeightMap = useRef({});
  var _g = __read(useState(200), 2), stateHeight = _g[0], setStateHeight = _g[1];
  var renderChild = useCacheChildrenNodes(children);
  useComputeVirtualItemHeight(refItemHeightMap);
  var itemCount = data.length;
  var itemHeight = propItemHeight || refItemHeightMap.current[KEY_VIRTUAL_ITEM_HEIGHT] || DEFAULT_VIRTUAL_ITEM_HEIGHT;
  var viewportHeight = isNumber(styleListMaxHeight) ? styleListMaxHeight : stateHeight;
  var itemCountVisible = Math.ceil(viewportHeight / itemHeight);
  var itemTotalHeight = itemHeight * itemCount;
  var isVirtual = threshold !== null && itemCount >= threshold && itemTotalHeight > viewportHeight;
  var refList = useRef(null);
  var refRafId = useRef(null);
  var refLockScroll = useRef(false);
  var refIsVirtual = useRef(isVirtual);
  var scrollListPadding = useMemo(function() {
    if (refList.current) {
      var getPadding = function(property) {
        return +window.getComputedStyle(refList.current)[property].replace(/\D/g, "");
      };
      return {
        top: getPadding("paddingTop"),
        bottom: getPadding("paddingBottom")
      };
    }
    return {
      top: 0,
      bottom: 0
    };
  }, [refList.current]);
  var _h = __read(useStateWithPromise({
    status: "NONE",
    startIndex: 0,
    endIndex: 0,
    itemIndex: 0,
    itemOffsetPtg: 0,
    startItemTop: 0,
    scrollTop: 0
  }), 2), state = _h[0], setState = _h[1];
  var prevData = usePrevious(data) || [];
  var isFirstRender = useIsFirstRender();
  var getItemKey = function(item, index) {
    return typeof itemKey === "function" ? itemKey(item, index) : typeof itemKey === "string" ? item[itemKey] : item.key || index;
  };
  var getItemKeyByIndex = function(index, items) {
    if (items === void 0) {
      items = data;
    }
    if (index === items.length) {
      return GHOST_ITEM_KEY;
    }
    var item = items[index];
    return item !== void 0 ? getItemKey(item, index) : null;
  };
  var getCachedItemHeight = function(key) {
    return refItemHeightMap.current[key] || itemHeight;
  };
  var internalScrollTo = function(relativeScroll) {
    var compareItemIndex = relativeScroll.itemIndex, compareItemRelativeTop = relativeScroll.relativeTop;
    var _a2 = refList.current, scrollHeight = _a2.scrollHeight, clientHeight = _a2.clientHeight;
    var originScrollTop = state.scrollTop;
    var maxScrollTop = scrollHeight - clientHeight;
    var bestSimilarity = Number.MAX_VALUE;
    var bestScrollTop = null;
    var bestItemIndex = null;
    var bestItemOffsetPtg = null;
    var bestStartIndex = null;
    var bestEndIndex = null;
    var missSimilarity = 0;
    for (var i = 0; i < maxScrollTop; i++) {
      var scrollTop = getIndexByStartLoc(0, maxScrollTop, originScrollTop, i);
      var scrollPtg = getScrollPercentage({
        scrollTop,
        scrollHeight,
        clientHeight
      });
      var _b2 = getRangeIndex(scrollPtg, itemCount, itemCountVisible), itemIndex = _b2.itemIndex, itemOffsetPtg = _b2.itemOffsetPtg, startIndex = _b2.startIndex, endIndex = _b2.endIndex;
      if (startIndex <= compareItemIndex && compareItemIndex <= endIndex) {
        var locatedItemRelativeTop = getItemRelativeTop({
          itemHeight: getCachedItemHeight(getItemKeyByIndex(itemIndex)),
          itemOffsetPtg,
          clientHeight,
          scrollPtg
        });
        var compareItemTop = getCompareItemRelativeTop({
          locatedItemRelativeTop,
          locatedItemIndex: itemIndex,
          compareItemIndex,
          startIndex,
          endIndex,
          itemHeight,
          getItemKey: getItemKeyByIndex,
          itemElementHeights: refItemHeightMap.current
        });
        var similarity = Math.abs(compareItemTop - compareItemRelativeTop);
        if (similarity < bestSimilarity) {
          bestSimilarity = similarity;
          bestScrollTop = scrollTop;
          bestItemIndex = itemIndex;
          bestItemOffsetPtg = itemOffsetPtg;
          bestStartIndex = startIndex;
          bestEndIndex = endIndex;
          missSimilarity = 0;
        } else {
          missSimilarity += 1;
        }
      }
      if (missSimilarity > 10) {
        break;
      }
    }
    if (bestScrollTop !== null) {
      refLockScroll.current = true;
      refList.current.scrollTop = bestScrollTop;
      setState(__assign(__assign({}, state), {
        status: "MEASURE_START",
        scrollTop: bestScrollTop,
        itemIndex: bestItemIndex,
        itemOffsetPtg: bestItemOffsetPtg,
        startIndex: bestStartIndex,
        endIndex: bestEndIndex
      }));
    }
    refRafId.current = raf(function() {
      refLockScroll.current = false;
    });
  };
  var rawListScrollHandler = function(event) {
    var _a2 = refList.current, rawScrollTop = _a2.scrollTop, clientHeight = _a2.clientHeight, scrollHeight = _a2.scrollHeight;
    var scrollTop = getValidScrollTop(rawScrollTop, scrollHeight - clientHeight);
    var scrollPtg = getScrollPercentage({
      scrollTop,
      clientHeight,
      scrollHeight
    });
    var _b2 = getLocationItem(scrollPtg, itemCount), index = _b2.index, offsetPtg = _b2.offsetPtg;
    setState(__assign(__assign({}, state), {
      scrollTop,
      itemIndex: index,
      itemOffsetPtg: offsetPtg
    }));
    event && onScroll && onScroll(event);
  };
  var virtualListScrollHandler = function(event, isInit) {
    if (isInit === void 0) {
      isInit = false;
    }
    var _a2 = refList.current, rawScrollTop = _a2.scrollTop, clientHeight = _a2.clientHeight, scrollHeight = _a2.scrollHeight;
    var scrollTop = getValidScrollTop(rawScrollTop, scrollHeight - clientHeight);
    if (!isInit && (scrollTop === state.scrollTop || refLockScroll.current)) {
      return;
    }
    var scrollPtg = getScrollPercentage({
      scrollTop,
      clientHeight,
      scrollHeight
    });
    var _b2 = getRangeIndex(scrollPtg, itemCount, itemCountVisible), itemIndex = _b2.itemIndex, itemOffsetPtg = _b2.itemOffsetPtg, startIndex = _b2.startIndex, endIndex = _b2.endIndex;
    setState(__assign(__assign({}, state), {
      scrollTop,
      itemIndex,
      itemOffsetPtg,
      startIndex,
      endIndex,
      status: "MEASURE_START"
    }));
    event && onScroll && onScroll(event);
  };
  useEffect(function() {
    return function() {
      refRafId.current && caf(refRafId.current);
    };
  }, []);
  useEffect(function() {
    if (refList.current) {
      if (isFirstRender) {
        refList.current.scrollTop = 0;
      }
      virtualListScrollHandler(null, true);
    }
  }, [itemCountVisible]);
  useEffect(function() {
    var changedItemIndex = null;
    var switchTo = refIsVirtual.current !== isVirtual ? isVirtual ? "virtual" : "raw" : "";
    refIsVirtual.current = isVirtual;
    if (viewportHeight && prevData.length !== data.length) {
      var diff = findListDiffIndex(prevData, data, getItemKey);
      changedItemIndex = diff ? diff.index : null;
    }
    if (switchTo || isVirtual && changedItemIndex) {
      var clientHeight = refList.current.clientHeight;
      var locatedItemRelativeTop = getItemRelativeTop({
        itemHeight: getCachedItemHeight(getItemKeyByIndex(state.itemIndex, prevData)),
        itemOffsetPtg: state.itemOffsetPtg,
        scrollPtg: getScrollPercentage({
          scrollTop: state.scrollTop,
          scrollHeight: prevData.length * itemHeight,
          clientHeight
        }),
        clientHeight
      });
      if (switchTo === "raw") {
        var rawTop = locatedItemRelativeTop;
        for (var index = 0; index < state.itemIndex; index++) {
          rawTop -= getCachedItemHeight(getItemKeyByIndex(index));
        }
        refList.current.scrollTop = -rawTop;
        refLockScroll.current = true;
        refRafId.current = raf(function() {
          refLockScroll.current = false;
        });
      } else {
        internalScrollTo({
          itemIndex: state.itemIndex,
          relativeTop: locatedItemRelativeTop
        });
      }
    }
  }, [data, isVirtual]);
  useIsomorphicLayoutEffect(function() {
    if (state.status === "MEASURE_START") {
      var _a2 = refList.current, scrollTop = _a2.scrollTop, scrollHeight = _a2.scrollHeight, clientHeight = _a2.clientHeight;
      var scrollPtg = getScrollPercentage({
        scrollTop,
        scrollHeight,
        clientHeight
      });
      var startItemTop = getItemAbsoluteTop({
        scrollPtg,
        clientHeight,
        scrollTop: scrollTop - (scrollListPadding.top + scrollListPadding.bottom) * scrollPtg,
        itemHeight: getCachedItemHeight(getItemKeyByIndex(state.itemIndex)),
        itemOffsetPtg: state.itemOffsetPtg
      });
      for (var index = state.itemIndex - 1; index >= state.startIndex; index--) {
        startItemTop -= getCachedItemHeight(getItemKeyByIndex(index));
      }
      setState(__assign(__assign({}, state), {
        startItemTop,
        status: "MEASURE_DONE"
      }));
    }
  }, [state]);
  useImperativeHandle(ref, function() {
    return {
      dom: refList.current,
      scrollTo: function(arg) {
        refRafId.current && caf(refRafId.current);
        refRafId.current = raf(function() {
          var _a2;
          if (typeof arg === "number") {
            refList.current.scrollTop = arg;
            return;
          }
          var index = "index" in arg ? arg.index : "key" in arg ? data.findIndex(function(item2, index2) {
            return getItemKey(item2, index2) === arg.key;
          }) : 0;
          var item = data[index];
          if (!item) {
            return;
          }
          var align = typeof arg === "object" && ((_a2 = arg.options) === null || _a2 === void 0 ? void 0 : _a2.block) ? arg.options.block : (scrollOptions === null || scrollOptions === void 0 ? void 0 : scrollOptions.block) || "nearest";
          var _b2 = refList.current, clientHeight = _b2.clientHeight, scrollTop = _b2.scrollTop;
          if (isVirtual && !isStaticItemHeight) {
            if (align === "nearest") {
              var itemIndex = state.itemIndex, itemOffsetPtg = state.itemOffsetPtg;
              if (Math.abs(itemIndex - index) < itemCountVisible) {
                var itemTop = getItemRelativeTop({
                  itemHeight: getCachedItemHeight(getItemKeyByIndex(itemIndex)),
                  itemOffsetPtg,
                  clientHeight,
                  scrollPtg: getScrollPercentage(refList.current)
                });
                if (index < itemIndex) {
                  for (var i = index; i < itemIndex; i++) {
                    itemTop -= getCachedItemHeight(getItemKeyByIndex(i));
                  }
                } else {
                  for (var i = itemIndex; i < index; i++) {
                    itemTop += getCachedItemHeight(getItemKeyByIndex(i));
                  }
                }
                if (itemTop < 0 || itemTop > clientHeight) {
                  align = itemTop < 0 ? "start" : "end";
                } else {
                  return;
                }
              } else {
                align = index < itemIndex ? "start" : "end";
              }
            }
            setState(__assign(__assign({}, state), {
              startIndex: Math.max(0, index - itemCountVisible),
              endIndex: Math.min(itemCount - 1, index + itemCountVisible)
            })).then(function() {
              var itemHeight2 = getCachedItemHeight(getItemKey(item, index));
              internalScrollTo({
                itemIndex: index,
                relativeTop: align === "start" ? 0 : (clientHeight - itemHeight2) / (align === "center" ? 2 : 1)
              });
            });
          } else {
            var indexItemHeight = getCachedItemHeight(getItemKeyByIndex(index));
            var itemTop = 0;
            for (var i = 0; i < index; i++) {
              itemTop += getCachedItemHeight(getItemKeyByIndex(i));
            }
            var itemBottom = itemTop + indexItemHeight;
            var itemMiddle = itemTop + indexItemHeight / 2;
            if (itemMiddle > scrollTop && itemMiddle < clientHeight + scrollTop) {
              return;
            }
            if (align === "nearest") {
              if (itemTop < scrollTop) {
                align = "start";
              } else if (itemBottom > scrollTop + clientHeight) {
                align = "end";
              }
            }
            var viewportHeight_1 = clientHeight - indexItemHeight;
            refList.current.scrollTop = itemTop - (align === "start" ? 0 : viewportHeight_1 / (align === "center" ? 2 : 1));
          }
        });
      }
    };
  }, [data, itemHeight, state]);
  var renderChildren = function(list, startIndex) {
    return list.map(function(item, index) {
      var originIndex = startIndex + index;
      var node = renderChild(item, originIndex, {
        style: {}
      });
      var key = getItemKey(item, originIndex);
      return React__default.cloneElement(node, {
        key,
        ref: function(ele) {
          var heightMap = refItemHeightMap.current;
          if (ele && state.status === "MEASURE_START" && (!isStaticItemHeight || heightMap[key] === void 0)) {
            if (isStaticItemHeight) {
              if (!heightMap[KEY_VIRTUAL_ITEM_HEIGHT]) {
                heightMap[KEY_VIRTUAL_ITEM_HEIGHT] = getNodeHeight(ele);
              }
              heightMap[key] = heightMap[KEY_VIRTUAL_ITEM_HEIGHT];
            } else {
              heightMap[key] = getNodeHeight(ele);
            }
          }
        }
      });
    });
  };
  var refLongestItemIndex = useRef(null);
  useEffect(function() {
    refLongestItemIndex.current = null;
  }, [data]);
  var renderLongestItem = function() {
    if (measureLongestItem) {
      var index = refLongestItemIndex.current === null ? getLongestItemIndex(data) : refLongestItemIndex.current;
      var item = data[index];
      refLongestItemIndex.current = index;
      return item ? /* @__PURE__ */ jsx("div", {
        style: {
          height: 1,
          overflow: "hidden",
          opacity: 0
        },
        children: renderChild(item, index, {
          style: {}
        })
      }) : null;
    }
    return null;
  };
  return /* @__PURE__ */ jsx(ResizeObserver, {
    onResize: function() {
      if (refList.current && !isNumber(styleListMaxHeight)) {
        var clientHeight = refList.current.clientHeight;
        setStateHeight(clientHeight);
      }
    },
    children: /* @__PURE__ */ jsx(WrapperTagName, {
      ...__assign({
        ref: refList,
        style: __assign(__assign({
          overflowY: "auto",
          overflowAnchor: "none"
        }, style), {
          maxHeight: styleListMaxHeight
        }),
        className,
        onScroll: isVirtual ? virtualListScrollHandler : rawListScrollHandler
      }, restProps),
      children: isVirtual ? /* @__PURE__ */ jsxs(Fragment, {
        children: [/* @__PURE__ */ jsx(Filler, {
          height: itemTotalHeight,
          offset: state.status === "MEASURE_DONE" ? state.startItemTop : 0,
          outerStyle,
          children: renderChildren(data.slice(state.startIndex, state.endIndex + 1), state.startIndex)
        }), renderLongestItem()]
      }) : needFiller ? /* @__PURE__ */ jsx(Filler, {
        height: viewportHeight,
        children: renderChildren(data, 0)
      }) : renderChildren(data, 0)
    })
  });
});
VirtualList.displayName = "VirtualList";
const VirtualList$1 = VirtualList;
export {
  VirtualList$1 as default
};
//# sourceMappingURL=index.js.map
