import { Box, Spacer, Text, useInput } from "ink";
import {
  useEffect,
  useMemo,
  useState,
  type ComponentType,
  type ReactNode,
} from "react";

export function ListDisplay<T>({
  items,
  Component,
  height,
  isFocused,
  status,
  onSelect,
}: {
  items: T[];
  Component: ComponentType<{ item: T; selected: boolean }>;
  height: number;
  isFocused?: boolean;
  status?: ReactNode;
  onSelect?: (item: T) => void;
}) {
  const [start, setStart] = useState(0);
  const slice = Math.min(start + height - 1, items.length);
  const [selected, setSelected] = useState(0);

  useInput(
    (input, key) => {
      if (key.upArrow) {
        setSelected((prev) => (prev > 0 ? prev - 1 : items.length - 1));
      } else if (key.downArrow) {
        setSelected((prev) => (prev + 1) % items.length);
      } else if (input === " " || key.return) {
        onSelect?.(items[selected]);
      }
    },
    { isActive: isFocused }
  );

  useEffect(() => {
    if (selected < start) setStart(selected);
    else if (selected >= slice)
      setStart(
        Math.max(Math.min(selected - slice + start + 1, items.length - 1), 0)
      );
  }, [selected, start, slice, items.length]);
  useEffect(() => {
    if (selected < 0) setSelected(Math.max(items.length - 1, 0));
    if (selected >= items.length) setSelected(0);
  }, [selected, items.length]);
  useEffect(() => {
    setSelected(0);
  }, [items]);

  const indexed = useMemo(
    () => items.map((item, index) => ({ item, index })),
    [items]
  );

  return (
    <Box flexDirection="column">
      <Box flexDirection="column">
        {indexed.slice(start, slice).map(({ item, index }) => (
          <Component
            key={index}
            item={item}
            selected={selected === index && isFocused !== false}
          />
        ))}
        {items.length < height - 1 && (
          <Box height={height - 1 - items.length} />
        )}
      </Box>
      <Box justifyContent="space-between">
        {status}
        <Spacer />
        <Text color="magenta">
          {items.length ? (
            <>
              {start + 1}-{slice}/{items.length}
            </>
          ) : (
            <>(empty)</>
          )}
        </Text>
      </Box>
    </Box>
  );
}
