"use strict";
var __defProp = Object.defineProperty;
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
var __getOwnPropNames = Object.getOwnPropertyNames;
var __hasOwnProp = Object.prototype.hasOwnProperty;
var __export = (target, all) => {
  for (var name in all)
    __defProp(target, name, { get: all[name], enumerable: true });
};
var __copyProps = (to, from, except, desc) => {
  if (from && typeof from === "object" || typeof from === "function") {
    for (let key of __getOwnPropNames(from))
      if (!__hasOwnProp.call(to, key) && key !== except)
        __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
  }
  return to;
};
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
var VirtualizedList_exports = {};
__export(VirtualizedList_exports, {
  SCROLL_TO_ITEM_END: () => SCROLL_TO_ITEM_END,
  VirtualizedList: () => VirtualizedList
});
module.exports = __toCommonJS(VirtualizedList_exports);
var import_jsx_runtime = require("react/jsx-runtime");
var import_react = require("react");
var import_ink = require("ink");
var import_useBatchedScroll = require("../../hooks/useBatchedScroll.js");
const SCROLL_TO_ITEM_END = Number.MAX_SAFE_INTEGER;
function findLastIndex(array, predicate) {
  for (let i = array.length - 1; i >= 0; i--) {
    if (predicate(array[i], i, array)) {
      return i;
    }
  }
  return -1;
}
function VirtualizedListInner(props, ref) {
  const {
    data,
    renderItem,
    estimatedItemHeight,
    keyExtractor,
    initialScrollIndex,
    initialScrollOffsetInIndex
  } = props;
  const dataRef = (0, import_react.useRef)(data);
  (0, import_react.useEffect)(() => {
    dataRef.current = data;
  }, [data]);
  const [scrollAnchor, setScrollAnchor] = (0, import_react.useState)(() => {
    const scrollToEnd = initialScrollIndex === SCROLL_TO_ITEM_END || typeof initialScrollIndex === "number" && initialScrollIndex >= data.length - 1 && initialScrollOffsetInIndex === SCROLL_TO_ITEM_END;
    if (scrollToEnd) {
      return {
        index: data.length > 0 ? data.length - 1 : 0,
        offset: SCROLL_TO_ITEM_END
      };
    }
    if (typeof initialScrollIndex === "number") {
      return {
        index: Math.max(0, Math.min(data.length - 1, initialScrollIndex)),
        offset: initialScrollOffsetInIndex ?? 0
      };
    }
    return { index: 0, offset: 0 };
  });
  const [isStickingToBottom, setIsStickingToBottom] = (0, import_react.useState)(() => {
    const scrollToEnd = initialScrollIndex === SCROLL_TO_ITEM_END || typeof initialScrollIndex === "number" && initialScrollIndex >= data.length - 1 && initialScrollOffsetInIndex === SCROLL_TO_ITEM_END;
    return scrollToEnd;
  });
  const containerRef = (0, import_react.useRef)(null);
  const [containerHeight, setContainerHeight] = (0, import_react.useState)(0);
  const itemRefs = (0, import_react.useRef)([]);
  const [heights, setHeights] = (0, import_react.useState)([]);
  const isInitialScrollSet = (0, import_react.useRef)(false);
  const { totalHeight, offsets } = (0, import_react.useMemo)(() => {
    const offsets2 = [0];
    let totalHeight2 = 0;
    for (let i = 0; i < data.length; i++) {
      const height = heights[i] ?? estimatedItemHeight(i);
      totalHeight2 += height;
      offsets2.push(totalHeight2);
    }
    return { totalHeight: totalHeight2, offsets: offsets2 };
  }, [heights, data, estimatedItemHeight]);
  (0, import_react.useEffect)(() => {
    setHeights((prevHeights) => {
      if (data.length === prevHeights.length) {
        return prevHeights;
      }
      const newHeights = [...prevHeights];
      if (data.length < prevHeights.length) {
        newHeights.length = data.length;
      } else {
        for (let i = prevHeights.length; i < data.length; i++) {
          newHeights[i] = estimatedItemHeight(i);
        }
      }
      return newHeights;
    });
  }, [data, estimatedItemHeight]);
  const scrollableContainerHeight = containerRef.current ? Math.round((0, import_ink.measureElement)(containerRef.current).height) : containerHeight;
  const getAnchorForScrollTop = (0, import_react.useCallback)(
    (scrollTop2, offsets2) => {
      const index = findLastIndex(offsets2, (offset) => offset <= scrollTop2);
      if (index === -1) {
        return { index: 0, offset: 0 };
      }
      return { index, offset: scrollTop2 - offsets2[index] };
    },
    []
  );
  const scrollTop = (0, import_react.useMemo)(() => {
    const offset = offsets[scrollAnchor.index];
    if (typeof offset !== "number") {
      return 0;
    }
    let rawScrollTop;
    if (scrollAnchor.offset === SCROLL_TO_ITEM_END) {
      const itemHeight = heights[scrollAnchor.index] ?? 0;
      rawScrollTop = offset + itemHeight - scrollableContainerHeight;
    } else {
      rawScrollTop = offset + scrollAnchor.offset;
    }
    const maxScroll = Math.max(0, totalHeight - scrollableContainerHeight);
    return Math.max(0, Math.min(maxScroll, rawScrollTop));
  }, [scrollAnchor, offsets, heights, scrollableContainerHeight, totalHeight]);
  const startIndex = Math.max(0, findLastIndex(offsets, (offset) => offset <= scrollTop) - 1);
  const endIndexOffset = offsets.findIndex(
    (offset) => offset > scrollTop + scrollableContainerHeight
  );
  const endIndex = endIndexOffset === -1 ? data.length - 1 : Math.min(data.length - 1, endIndexOffset);
  (0, import_react.useLayoutEffect)(() => {
    if (containerRef.current) {
      const height = Math.round((0, import_ink.measureElement)(containerRef.current).height);
      if (containerHeight !== height) {
        setContainerHeight(height);
      }
    }
    let newHeights = null;
    for (let i = startIndex; i <= endIndex; i++) {
      const itemRef = itemRefs.current[i];
      if (itemRef) {
        const height = Math.round((0, import_ink.measureElement)(itemRef).height);
        if (height !== heights[i]) {
          if (!newHeights) {
            newHeights = [...heights];
          }
          newHeights[i] = height;
        }
      }
    }
    if (newHeights) {
      setHeights(newHeights);
    }
  });
  const prevDataLength = (0, import_react.useRef)(data.length);
  const prevTotalHeight = (0, import_react.useRef)(totalHeight);
  const prevScrollTop = (0, import_react.useRef)(scrollTop);
  const prevContainerHeight = (0, import_react.useRef)(scrollableContainerHeight);
  (0, import_react.useLayoutEffect)(() => {
    const contentPreviouslyFit = prevTotalHeight.current <= prevContainerHeight.current;
    const wasScrolledToBottomPixels = prevScrollTop.current >= prevTotalHeight.current - prevContainerHeight.current - 1;
    const wasAtBottom = contentPreviouslyFit || wasScrolledToBottomPixels;
    if (wasAtBottom && scrollTop >= prevScrollTop.current) {
      setIsStickingToBottom(true);
    }
    const listGrew = data.length > prevDataLength.current;
    const containerChanged = prevContainerHeight.current !== scrollableContainerHeight;
    if (listGrew && (isStickingToBottom || wasAtBottom) || isStickingToBottom && containerChanged) {
      setScrollAnchor({
        index: data.length > 0 ? data.length - 1 : 0,
        offset: SCROLL_TO_ITEM_END
      });
      if (!isStickingToBottom) {
        setIsStickingToBottom(true);
      }
    } else if ((scrollAnchor.index >= data.length || scrollTop > totalHeight - scrollableContainerHeight) && data.length > 0) {
      const newScrollTop = Math.max(0, totalHeight - scrollableContainerHeight);
      setScrollAnchor(getAnchorForScrollTop(newScrollTop, offsets));
    } else if (data.length === 0) {
      setScrollAnchor({ index: 0, offset: 0 });
    }
    prevDataLength.current = data.length;
    prevTotalHeight.current = totalHeight;
    prevScrollTop.current = scrollTop;
    prevContainerHeight.current = scrollableContainerHeight;
  }, [
    data.length,
    totalHeight,
    scrollTop,
    scrollableContainerHeight,
    scrollAnchor.index,
    getAnchorForScrollTop,
    offsets,
    isStickingToBottom
  ]);
  (0, import_react.useLayoutEffect)(() => {
    if (isInitialScrollSet.current || offsets.length <= 1 || totalHeight <= 0 || containerHeight <= 0) {
      return;
    }
    if (typeof initialScrollIndex === "number") {
      const scrollToEnd = initialScrollIndex === SCROLL_TO_ITEM_END || initialScrollIndex >= data.length - 1 && initialScrollOffsetInIndex === SCROLL_TO_ITEM_END;
      if (scrollToEnd) {
        setScrollAnchor({
          index: data.length - 1,
          offset: SCROLL_TO_ITEM_END
        });
        setIsStickingToBottom(true);
        isInitialScrollSet.current = true;
        return;
      }
      const index = Math.max(0, Math.min(data.length - 1, initialScrollIndex));
      const offset = initialScrollOffsetInIndex ?? 0;
      const newScrollTop = (offsets[index] ?? 0) + offset;
      const clampedScrollTop = Math.max(
        0,
        Math.min(totalHeight - scrollableContainerHeight, newScrollTop)
      );
      setScrollAnchor(getAnchorForScrollTop(clampedScrollTop, offsets));
      isInitialScrollSet.current = true;
    }
  }, [
    initialScrollIndex,
    initialScrollOffsetInIndex,
    offsets,
    totalHeight,
    containerHeight,
    getAnchorForScrollTop,
    data.length,
    scrollableContainerHeight
  ]);
  const topSpacerHeight = offsets[startIndex] ?? 0;
  const bottomSpacerHeight = totalHeight - (offsets[endIndex + 1] ?? totalHeight);
  const renderedItems = [];
  for (let i = startIndex; i <= endIndex; i++) {
    const item = data[i];
    if (item) {
      renderedItems.push(
        /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
          import_ink.Box,
          {
            width: "100%",
            ref: (el) => {
              itemRefs.current[i] = el;
            },
            children: renderItem({ item, index: i })
          },
          keyExtractor(item, i)
        )
      );
    }
  }
  const { getScrollTop, setPendingScrollTop } = (0, import_useBatchedScroll.useBatchedScroll)(scrollTop);
  (0, import_react.useImperativeHandle)(
    ref,
    () => ({
      scrollBy: (delta) => {
        if (delta < 0) {
          setIsStickingToBottom(false);
        }
        const currentScrollTop = getScrollTop();
        const newScrollTop = Math.max(
          0,
          Math.min(totalHeight - scrollableContainerHeight, currentScrollTop + delta)
        );
        setPendingScrollTop(newScrollTop);
        setScrollAnchor(getAnchorForScrollTop(newScrollTop, offsets));
      },
      scrollTo: (offset) => {
        setIsStickingToBottom(false);
        const newScrollTop = Math.max(
          0,
          Math.min(totalHeight - scrollableContainerHeight, offset)
        );
        setPendingScrollTop(newScrollTop);
        setScrollAnchor(getAnchorForScrollTop(newScrollTop, offsets));
      },
      scrollToEnd: () => {
        setIsStickingToBottom(true);
        if (data.length > 0) {
          setScrollAnchor({
            index: data.length - 1,
            offset: SCROLL_TO_ITEM_END
          });
        }
      },
      scrollToIndex: ({ index, viewOffset = 0, viewPosition = 0 }) => {
        setIsStickingToBottom(false);
        const offset = offsets[index];
        if (offset !== void 0) {
          const newScrollTop = Math.max(
            0,
            Math.min(
              totalHeight - scrollableContainerHeight,
              offset - viewPosition * scrollableContainerHeight + viewOffset
            )
          );
          setPendingScrollTop(newScrollTop);
          setScrollAnchor(getAnchorForScrollTop(newScrollTop, offsets));
        }
      },
      scrollToItem: ({ item, viewOffset = 0, viewPosition = 0 }) => {
        setIsStickingToBottom(false);
        const index = data.indexOf(item);
        if (index !== -1) {
          const offset = offsets[index];
          if (offset !== void 0) {
            const newScrollTop = Math.max(
              0,
              Math.min(
                totalHeight - scrollableContainerHeight,
                offset - viewPosition * scrollableContainerHeight + viewOffset
              )
            );
            setPendingScrollTop(newScrollTop);
            setScrollAnchor(getAnchorForScrollTop(newScrollTop, offsets));
          }
        }
      },
      getScrollIndex: () => scrollAnchor.index,
      getScrollState: () => ({
        scrollTop: getScrollTop(),
        scrollHeight: totalHeight,
        innerHeight: containerHeight
      })
    }),
    [
      offsets,
      scrollAnchor,
      totalHeight,
      getAnchorForScrollTop,
      data,
      scrollableContainerHeight,
      getScrollTop,
      setPendingScrollTop,
      containerHeight
    ]
  );
  return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
    import_ink.Box,
    {
      ref: containerRef,
      overflowY: "scroll",
      overflowX: "hidden",
      scrollTop,
      scrollbarThumbColor: props.scrollbarThumbColor ?? "gray",
      width: "100%",
      height: "100%",
      flexDirection: "column",
      paddingRight: 1,
      children: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_ink.Box, { flexShrink: 0, width: "100%", flexDirection: "column", children: [
        /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_ink.Box, { height: topSpacerHeight, flexShrink: 0 }),
        renderedItems,
        /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_ink.Box, { height: bottomSpacerHeight, flexShrink: 0 })
      ] })
    }
  );
}
const VirtualizedList = (0, import_react.forwardRef)(VirtualizedListInner);
// Annotate the CommonJS export names for ESM import in node:
0 && (module.exports = {
  SCROLL_TO_ITEM_END,
  VirtualizedList
});
