import React, { useRef, useEffect, useState, useCallback } from 'react';
import { useVirtualizer } from '@tanstack/react-virtual';

export interface VirtualizedListProps<T> {
  items: T[];
  itemHeight: number;
  containerHeight: number;
  renderItem: (item: T, index: number) => React.ReactNode;
  className?: string;
  overscan?: number;
  onScroll?: (scrollTop: number) => void;
  onItemsRendered?: (startIndex: number, endIndex: number) => void;
}

export function VirtualizedList<T>({
  items,
  itemHeight,
  containerHeight,
  renderItem,
  className = '',
  overscan = 5,
  onScroll,
  onItemsRendered,
}: VirtualizedListProps<T>) {
  const parentRef = useRef<HTMLDivElement>(null);
  // eslint-disable-next-line @typescript-eslint/no-unused-vars
  const [isScrolling, setIsScrolling] = useState(false);
  const scrollTimeoutRef = useRef<NodeJS.Timeout>();

  const virtualizer = useVirtualizer({
    count: items.length,
    getScrollElement: () => parentRef.current,
    estimateSize: () => itemHeight,
    overscan,
  });

  const virtualItems = virtualizer.getVirtualItems();

  // Handle scroll events with debouncing
  const handleScroll = useCallback(() => {
    setIsScrolling(true);
    
    if (scrollTimeoutRef.current) {
      clearTimeout(scrollTimeoutRef.current);
    }
    
    scrollTimeoutRef.current = setTimeout(() => {
      setIsScrolling(false);
    }, 150);

    if (onScroll && parentRef.current) {
      onScroll(parentRef.current.scrollTop);
    }

    if (onItemsRendered && virtualItems.length > 0) {
      const startIndex = virtualItems[0].index;
      const endIndex = virtualItems[virtualItems.length - 1].index;
      onItemsRendered(startIndex, endIndex);
    }
  }, [onScroll, onItemsRendered, virtualItems]);

  useEffect(() => {
    const scrollElement = parentRef.current;
    if (scrollElement) {
      scrollElement.addEventListener('scroll', handleScroll, { passive: true });
      return () => scrollElement.removeEventListener('scroll', handleScroll);
    }
  }, [handleScroll]);

  // Cleanup timeout on unmount
  useEffect(() => {
    return () => {
      if (scrollTimeoutRef.current) {
        clearTimeout(scrollTimeoutRef.current);
      }
    };
  }, []);

  const totalSize = virtualizer.getTotalSize();
  const paddingTop = virtualItems.length > 0 ? virtualItems[0]?.start || 0 : 0;
  const paddingBottom = totalSize - (virtualItems.length > 0 ? virtualItems[virtualItems.length - 1]?.end || 0 : 0);

  return (
    <div
      ref={parentRef}
      className={`overflow-auto ${className}`}
      style={{ height: containerHeight }}
    >
      <div
        style={{
          height: totalSize,
          width: '100%',
          position: 'relative',
        }}
      >
        {paddingTop > 0 && <div style={{ height: paddingTop }} />}
        {virtualItems.map((virtualItem) => (
          <div
            key={virtualItem.key}
            data-index={virtualItem.index}
            ref={virtualizer.measureElement}
            style={{
              position: 'absolute',
              top: 0,
              left: 0,
              width: '100%',
              transform: `translateY(${virtualItem.start}px)`,
            }}
          >
            {renderItem(items[virtualItem.index], virtualItem.index)}
          </div>
        ))}
        {paddingBottom > 0 && <div style={{ height: paddingBottom }} />}
      </div>
    </div>
  );
}

// Hook for infinite scrolling
export function useInfiniteScroll<T>(
  items: T[],
  hasNextPage: boolean,
  isFetching: boolean,
  fetchNextPage: () => void,
  threshold: number = 5
) {
  const [isNearBottom, setIsNearBottom] = useState(false);

  const handleItemsRendered = useCallback(
    (startIndex: number, endIndex: number) => {
      const isNearEnd = endIndex >= items.length - threshold;
      setIsNearBottom(isNearEnd);
    },
    [items.length, threshold]
  );

  useEffect(() => {
    if (isNearBottom && hasNextPage && !isFetching) {
      fetchNextPage();
    }
  }, [isNearBottom, hasNextPage, isFetching, fetchNextPage]);

  return { handleItemsRendered };
}

// Hook for scroll position restoration
export function useScrollPosition(key: string) {
  const [scrollPosition, setScrollPosition] = useState(0);

  useEffect(() => {
    const saved = sessionStorage.getItem(`scroll-${key}`);
    if (saved) {
      setScrollPosition(parseInt(saved, 10));
    }
  }, [key]);

  const saveScrollPosition = useCallback((position: number) => {
    setScrollPosition(position);
    sessionStorage.setItem(`scroll-${key}`, position.toString());
  }, [key]);

  const restoreScrollPosition = useCallback((element: HTMLElement | null) => {
    if (element && scrollPosition > 0) {
      element.scrollTop = scrollPosition;
    }
  }, [scrollPosition]);

  return { scrollPosition, saveScrollPosition, restoreScrollPosition };
}
