import { Fragment, jsx, jsxs } from "react/jsx-runtime";
import {
  useState,
  useEffect,
  useRef,
  useMemo,
  useCallback,
  forwardRef,
  useImperativeHandle
} from "react";
import { Box, Text } from "ink";
import { useTerminalSize } from "../../hooks/useTerminalSize.js";
import { getMaxVisibleItemsForTerminalRows } from "../../utils/overlaySizing.js";
import { HintBar } from "../shared/HintBar.js";
function BaseSelectorInner({
  items,
  isVisible,
  isLoading = false,
  selectedIndex,
  onSelectIndex,
  onSelect,
  onClose,
  formatItem,
  title,
  maxVisibleItems = 8,
  loadingMessage = "Loading...",
  emptyMessage = "No items found",
  borderColor = "cyan",
  onTab,
  supportsTab = false,
  instructionsOverride
}, ref) {
  const { rows: terminalRows } = useTerminalSize();
  const viewportItems = useMemo(() => {
    return getMaxVisibleItemsForTerminalRows({
      rows: terminalRows,
      hardCap: maxVisibleItems,
      reservedRows: 14
    });
  }, [terminalRows, maxVisibleItems]);
  const [scrollOffsetState, setScrollOffset] = useState(0);
  const selectedIndexRef = useRef(selectedIndex);
  const prevItemsLengthRef = useRef(items.length);
  selectedIndexRef.current = selectedIndex;
  const scrollOffset = useMemo(() => {
    const itemsChanged = items.length !== prevItemsLengthRef.current;
    if (itemsChanged && items.length <= viewportItems) {
      return 0;
    }
    let offset = scrollOffsetState;
    if (selectedIndex < offset) {
      offset = selectedIndex;
    } else if (selectedIndex >= offset + viewportItems) {
      offset = Math.max(0, selectedIndex - viewportItems + 1);
    }
    const maxOffset = Math.max(0, items.length - viewportItems);
    return Math.min(maxOffset, Math.max(0, offset));
  }, [selectedIndex, items.length, viewportItems, scrollOffsetState]);
  useEffect(() => {
    prevItemsLengthRef.current = items.length;
  }, [items.length]);
  useEffect(() => {
    if (scrollOffset !== scrollOffsetState) {
      setScrollOffset(scrollOffset);
    }
  }, [scrollOffset, scrollOffsetState]);
  const handleSelectIndex = useCallback(
    (newIndex) => {
      selectedIndexRef.current = newIndex;
      onSelectIndex(newIndex);
    },
    [onSelectIndex]
  );
  const visibleItems = useMemo(() => {
    return items.slice(scrollOffset, scrollOffset + viewportItems);
  }, [items, scrollOffset, viewportItems]);
  useImperativeHandle(
    ref,
    () => ({
      handleInput: (_input, key) => {
        if (!isVisible) return false;
        if (key.escape) {
          onClose();
          return true;
        }
        const itemsLength = items.length;
        if (isLoading || itemsLength === 0) return true;
        if (key.upArrow) {
          const nextIndex = (selectedIndexRef.current - 1 + itemsLength) % itemsLength;
          handleSelectIndex(nextIndex);
          return true;
        }
        if (key.downArrow) {
          const nextIndex = (selectedIndexRef.current + 1) % itemsLength;
          handleSelectIndex(nextIndex);
          return true;
        }
        if (key.tab && onTab) {
          const item = items[selectedIndexRef.current];
          if (item !== void 0) {
            onTab(item);
            return true;
          }
        }
        if (key.return && itemsLength > 0) {
          const item = items[selectedIndexRef.current];
          if (item !== void 0) {
            onSelect(item);
            return true;
          }
        }
        return false;
      }
    }),
    [isVisible, isLoading, items, handleSelectIndex, onClose, onSelect, onTab]
  );
  if (!isVisible) return null;
  return /* @__PURE__ */ jsxs(Box, { flexDirection: "column", children: [
    /* @__PURE__ */ jsx(Box, { paddingX: 0, paddingY: 0, children: /* @__PURE__ */ jsx(Text, { color: borderColor, bold: true, children: title }) }),
    /* @__PURE__ */ jsx(Box, { flexDirection: "column", height: viewportItems, marginTop: 1, children: isLoading ? /* @__PURE__ */ jsxs(Fragment, { children: [
      /* @__PURE__ */ jsx(Box, { paddingX: 0, paddingY: 0, children: /* @__PURE__ */ jsx(Text, { color: "gray", children: loadingMessage }) }),
      Array.from({ length: Math.max(0, viewportItems - 1) }, (_, index) => /* @__PURE__ */ jsx(Box, { paddingX: 0, paddingY: 0, children: /* @__PURE__ */ jsx(Text, { children: " " }) }, `loading-spacer-${index}`))
    ] }) : items.length === 0 ? /* @__PURE__ */ jsxs(Fragment, { children: [
      /* @__PURE__ */ jsx(Box, { paddingX: 0, paddingY: 0, children: /* @__PURE__ */ jsx(Text, { color: "gray", children: emptyMessage }) }),
      Array.from({ length: Math.max(0, viewportItems - 1) }, (_, index) => /* @__PURE__ */ jsx(Box, { paddingX: 0, paddingY: 0, children: /* @__PURE__ */ jsx(Text, { children: " " }) }, `empty-spacer-${index}`))
    ] }) : Array.from({ length: viewportItems }, (_, rowIndex) => {
      const item = visibleItems[rowIndex];
      if (item === void 0) {
        return /* @__PURE__ */ jsx(Box, { paddingX: 0, paddingY: 0, children: /* @__PURE__ */ jsx(Text, { children: " " }) }, `item-empty-${rowIndex}`);
      }
      const actualIndex = scrollOffset + rowIndex;
      const isSelected = actualIndex === selectedIndex;
      return /* @__PURE__ */ jsx(Box, { paddingX: 0, paddingY: 0, children: formatItem(item, isSelected) }, actualIndex);
    }) }),
    /* @__PURE__ */ jsx(Box, { paddingX: 0, paddingY: 0, marginTop: 1, children: instructionsOverride ? /* @__PURE__ */ jsx(Text, { color: "gray", wrap: "truncate-end", children: instructionsOverride }) : /* @__PURE__ */ jsx(
      HintBar,
      {
        hints: [
          "\u2191\u2193 navigate",
          supportsTab ? "Tab load" : "",
          "Enter select",
          "Esc close"
        ]
      }
    ) })
  ] });
}
const BaseSelector = forwardRef(BaseSelectorInner);
export {
  BaseSelector
};
