'use client';

import {
  useCallback,
  useEffect,
  useImperativeHandle,
  useRef,
  type RefObject,
} from 'react';
import { Combobox } from '@base-ui/react/combobox';
import { useVirtualizer, type Virtualizer } from '@tanstack/react-virtual';
import { Loader2 } from 'lucide-react';

import { ComboboxItem } from '@/components/ui/combobox';
import { cn } from '@/lib/utils';

import type { AsyncSelectOption } from './AsyncSelect.types';

type VirtualizerHandle = Virtualizer<HTMLDivElement, Element>;
const LOAD_MORE_THRESHOLD = 3;

interface VirtualSelectListProps {
  open: boolean;
  virtualizerRef: RefObject<VirtualizerHandle | null>;
  hasNextPage: boolean;
  isFetchingNextPage: boolean;
  onLoadMore: () => void;
  estimateSize?: number;
}

export function VirtualSelectList({
  open,
  virtualizerRef,
  hasNextPage,
  isFetchingNextPage,
  onLoadMore,
  estimateSize = 36,
}: VirtualSelectListProps) {
  const filteredItems = Combobox.useFilteredItems<AsyncSelectOption>();
  const scrollElementRef = useRef<HTMLDivElement | null>(null);
  const itemCount = filteredItems.length + (hasNextPage ? 1 : 0);

  const virtualizer = useVirtualizer({
    enabled: open,
    count: itemCount,
    getScrollElement: () => scrollElementRef.current,
    estimateSize: () => estimateSize,
    overscan: 8,
    paddingStart: 4,
    paddingEnd: 4,
  });

  useImperativeHandle(virtualizerRef, () => virtualizer, [virtualizer]);

  const handleScrollElementRef = useCallback(
    (element: HTMLDivElement | null) => {
      scrollElementRef.current = element;
      if (element) {
        virtualizer.measure();
      }
    },
    [virtualizer],
  );

  const virtualItems = virtualizer.getVirtualItems();
  const totalSize = virtualizer.getTotalSize();
  const lastVirtualIndex = virtualItems[virtualItems.length - 1]?.index ?? -1;

  useEffect(() => {
    if (lastVirtualIndex < 0) {
      return;
    }

    if (
      lastVirtualIndex >= filteredItems.length - LOAD_MORE_THRESHOLD &&
      hasNextPage &&
      !isFetchingNextPage
    ) {
      onLoadMore();
    }
  }, [
    filteredItems.length,
    hasNextPage,
    isFetchingNextPage,
    lastVirtualIndex,
    onLoadMore,
  ]);

  if (!filteredItems.length && !hasNextPage) {
    return null;
  }

  return (
    <div
      ref={handleScrollElementRef}
      className={cn(
        'max-h-[min(18rem,calc(var(--available-height)-2.25rem))] overflow-y-auto overscroll-contain p-1',
      )}
      style={{ height: Math.min(totalSize + 8, 200) }}
    >
      <div className="relative w-full" style={{ height: totalSize }}>
        {virtualItems.map((virtualItem) => {
          const isLoaderRow = virtualItem.index >= filteredItems.length;
          const item = filteredItems[virtualItem.index];

          return (
            <div
              key={virtualItem.key}
              data-index={virtualItem.index}
              ref={virtualizer.measureElement}
              className="absolute top-0 left-0 w-full"
              style={{
                height: virtualItem.size,
                transform: `translateY(${virtualItem.start}px)`,
              }}
            >
              {isLoaderRow ? (
                <div className="flex items-center justify-center py-2 text-muted-foreground">
                  <Loader2 className="size-4 animate-spin" />
                </div>
              ) : (
                <ComboboxItem
                  value={item}
                  index={virtualItem.index}
                  aria-setsize={filteredItems.length}
                  aria-posinset={virtualItem.index + 1}
                >
                  {item.label}
                </ComboboxItem>
              )}
            </div>
          );
        })}
      </div>
    </div>
  );
}
