import React, { useState, useRef, useEffect, useCallback, useMemo, memo, startTransition } from 'react';
import {
  Box,
  Flex,
  Text,
  Button,
  IconButton,
  HStack,
  Checkbox,
  Spinner,
  useDisclosure,
  Input,
  InputGroup,
  InputLeftElement,
} from '@chakra-ui/react';
import { Search2Icon } from '@chakra-ui/icons';
import { FiPlay } from 'react-icons/fi';
import type { Song, PlaylistNode } from '../types/interfaces';
import { api } from '../services/api';
import { formatDuration, formatTotalDuration } from '../utils/formatters';
import { useDebounce } from '../hooks/useDebounce';
import { PlaylistSelectionModal } from './PlaylistSelectionModal';
import { useVirtualizer } from '@tanstack/react-virtual';
import type { VirtualItem } from '@tanstack/react-virtual';

interface PaginatedSongListProps {
  songs: Song[];
  onAddToPlaylist: (songIds: string[], playlistName: string) => void;
  onRemoveFromPlaylist?: (songIds: string[]) => void;
  playlists: PlaylistNode[];
  onSongSelect: (song: Song) => void;
  selectedSongId: string | null;
  currentPlaylist: string | null;
  loading: boolean;
  hasMore: boolean;
  totalSongs: number;
  totalPlaylistDuration?: string; // Total duration of the entire playlist
  onLoadMore: () => void;
  onSearch: (query: string) => void;
  searchQuery: string;
  depth?: number;
  isSwitchingPlaylist?: boolean; // New prop to indicate playlist switching
  onPlaySong?: (song: Song) => void; // New prop for playing songs
  onReorder?: (orderedIds: string[]) => Promise<void>;
}

// Memoized song item component to prevent unnecessary re-renders
const SongItem = memo<{
  song: Song;
  isSelected: boolean;
  isHighlighted: boolean;
  onSelect: (song: Song) => void;
  onToggleSelection: (songId: string) => void;
  showCheckbox: boolean;
  onPlaySong?: (song: Song) => void;
  showDropIndicatorTop?: boolean;
  onDragStart?: (e: React.DragEvent, songIdsFallback: string[]) => void;
  onRowDragOver?: (e: React.DragEvent) => void;
  onRowDrop?: (e: React.DragEvent) => void;
  onRowDragStartCapture?: (e: React.DragEvent) => void;
  index: number;
  onCheckboxToggle?: (index: number, checked: boolean, shift: boolean) => void;
}>(({ song, isSelected, isHighlighted, onSelect, onToggleSelection, showCheckbox, onPlaySong, showDropIndicatorTop, onDragStart, onRowDragOver, onRowDrop, onRowDragStartCapture, index, onCheckboxToggle }) => {
  // Memoize the formatted duration to prevent recalculation
  const formattedDuration = useMemo(() => formatDuration(song.totalTime || ''), [song.totalTime]);
  // Local optimistic selection for instant visual feedback
  const [localChecked, setLocalChecked] = useState<boolean>(isSelected);
  useEffect(() => {
    setLocalChecked(isSelected);
  }, [isSelected]);
  const handleClick = useCallback(() => {
    onSelect(song);
  }, [onSelect, song]);

  const handleCheckboxClick = useCallback((e: React.ChangeEvent<HTMLInputElement>) => {
    e.stopPropagation();
    setLocalChecked(e.target.checked);
    if (onCheckboxToggle) {
      onCheckboxToggle(index, e.target.checked, (e as any).nativeEvent?.shiftKey === true || (e as any).shiftKey === true);
    } else {
      onToggleSelection(song.id);
    }
  }, [onCheckboxToggle, index, onToggleSelection, song.id]);

  const handlePlayClick = useCallback((e: React.MouseEvent) => {
    e.stopPropagation();
    if (onPlaySong && (song.s3File?.hasS3File || song.hasMusicFile)) {
      onPlaySong(song);
    }
  }, [onPlaySong, song]);

  const hasMusicFile = (song: Song): boolean => {
    return song.s3File?.hasS3File || song.hasMusicFile || false;
  };

  return (
    <Flex
      key={song.id}
      p={3}
      borderBottom="1px"
      borderColor="gray.700"
      cursor="pointer"
      bg={isHighlighted ? "blue.900" : "transparent"}
      _hover={{ bg: isHighlighted ? "blue.800" : "gray.700" }}
      onClick={handleClick}
      transition="background-color 0.2s"
      {...(onDragStart ? { draggable: true, onDragStart: (e: React.DragEvent) => onDragStart(e, [song.id]) } : {})}
      {...(onRowDragOver ? { onDragOver: onRowDragOver } : {})}
      {...(onRowDrop ? { onDrop: onRowDrop } : {})}
      {...(onRowDragStartCapture ? { onDragStartCapture: onRowDragStartCapture } : {})}
      position="relative"
    >
      {showDropIndicatorTop && (
        <Box position="absolute" top={0} left={0} right={0} height="2px" bg="blue.400" zIndex={1} />
      )}
      {showCheckbox && (
        <Checkbox
          isChecked={localChecked}
          onChange={handleCheckboxClick}
          mr={3}
          onClick={(e) => e.stopPropagation()}
        />
      )}
      <Box flex={1} minW={0}>
        <Text fontSize="sm" fontWeight="medium" color="white" noOfLines={1}>
          {song.title}
        </Text>
        <Text fontSize="xs" color="gray.400" noOfLines={1}>
          {song.artist}
        </Text>
      </Box>
      <Box textAlign="right" ml={2}>
        <Text fontSize="xs" color="gray.500">
          {formattedDuration}
        </Text>
        <Text fontSize="xs" color="gray.600">
          {song.averageBpm} BPM
        </Text>
      </Box>
      {hasMusicFile(song) && onPlaySong && (
        <IconButton
          aria-label="Play song"
          icon={<FiPlay />}
          size="sm"
          variant="ghost"
          colorScheme="blue"
          onClick={handlePlayClick}
          ml={2}
          _hover={{ bg: "blue.900" }}
        />
      )}
    </Flex>
  );
});

SongItem.displayName = 'SongItem';

export const PaginatedSongList: React.FC<PaginatedSongListProps> = memo(({
  songs,
  onAddToPlaylist,
  onRemoveFromPlaylist,
  playlists,
  onSongSelect,
  selectedSongId,
  currentPlaylist,
  loading,
  hasMore,
  totalSongs,
  totalPlaylistDuration,
  onLoadMore,
  onSearch,
  searchQuery,
  depth = 0,
  isSwitchingPlaylist = false,
  onPlaySong,
  onReorder
}) => {
  const [selectedSongs, setSelectedSongs] = useState<Set<string>>(new Set());
  const dragSelectionRef = useRef<string[] | null>(null);
  const [isDragging, setIsDragging] = useState(false);
  const [localSearchQuery, setLocalSearchQuery] = useState(searchQuery);
  const { isOpen: isPlaylistModalOpen, onOpen: onPlaylistModalOpen, onClose: onPlaylistModalClose } = useDisclosure();
  const observerRef = useRef<IntersectionObserver | null>(null);
  const loadingRef = useRef<HTMLDivElement>(null);
  const scrollContainerRef = useRef<HTMLDivElement>(null);
  const isTriggeringRef = useRef(false);
  const timeoutRef = useRef<NodeJS.Timeout | null>(null);
  const [dragHoverIndex, setDragHoverIndex] = useState<number | null>(null);
  const [endDropHover, setEndDropHover] = useState<boolean>(false);
  const [isReorderDragging, setIsReorderDragging] = useState<boolean>(false);
  const lastSelectedIndexRef = useRef<number | null>(null);
  const dragPreviewRef = useRef<HTMLDivElement | null>(null);
  
  // Store current values in refs to avoid stale closures
  const hasMoreRef = useRef(hasMore);
  const loadingRef_state = useRef(loading);
  const onLoadMoreRef = useRef(onLoadMore);
  
  // Update refs when props change
  useEffect(() => {
    hasMoreRef.current = hasMore;
    loadingRef_state.current = loading;
    onLoadMoreRef.current = onLoadMore;
  }, [hasMore, loading, onLoadMore]);
  
  // Debounce search to prevent excessive API calls
  const debouncedSearchQuery = useDebounce(localSearchQuery, 300);

  // Memoized helper function to get all playlists (excluding folders) from the playlist tree
  const getAllPlaylists = useCallback((nodes: PlaylistNode[]): PlaylistNode[] => {
    if (!nodes || nodes.length === 0) return [];
    
    let result: PlaylistNode[] = [];
    for (const node of nodes) {
      if (node.type === 'playlist') {
        result.push(node);
      } else if (node.type === 'folder' && node.children) {
        result = result.concat(getAllPlaylists(node.children));
      }
    }
    return result;
  }, []);

  // Memoized flattened list of all playlists
  // const allPlaylists = useMemo(() => getAllPlaylists(playlists), [playlists, getAllPlaylists]);

  const toggleSelection = useCallback((songId: string) => {
    startTransition(() => {
      setSelectedSongs(prev => {
        const newSelection = new Set(prev);
        if (newSelection.has(songId)) {
          newSelection.delete(songId);
        } else {
          newSelection.add(songId);
        }
        return newSelection;
      });
    });
  }, []);

  // Range selection using shift-click between last selected and current
  const toggleSelectionRange = useCallback((fromIndex: number, toIndex: number, checked: boolean) => {
    if (fromIndex === null || toIndex === null) return;
    const [start, end] = fromIndex < toIndex ? [fromIndex, toIndex] : [toIndex, fromIndex];
    startTransition(() => {
      setSelectedSongs(prev => {
        const next = new Set(prev);
        for (let i = start; i <= end; i++) {
          const id = songs[i]?.id;
          if (!id) continue;
          if (checked) next.add(id); else next.delete(id);
        }
        return next;
      });
    });
  }, [songs]);

  const handleCheckboxToggle = useCallback((index: number, checked: boolean, shift: boolean) => {
    const song = songs[index];
    if (!song) return;
    if (shift && lastSelectedIndexRef.current !== null) {
      toggleSelectionRange(lastSelectedIndexRef.current, index, checked);
    } else {
      toggleSelection(song.id);
    }
    lastSelectedIndexRef.current = index;
  }, [songs, toggleSelection, toggleSelectionRange]);

  const toggleSelectAll = useCallback(() => {
    startTransition(() => {
      setSelectedSongs(prev => {
        const noneSelected = prev.size === 0;
        const allSelected = prev.size === songs.length && songs.length > 0;
        if (noneSelected) {
          return new Set(songs.map(s => s.id));
        }
        if (allSelected) {
          return new Set();
        }
        return new Set(songs.map(s => s.id));
      });
    });
  }, [songs]);

  const handleBulkAddToPlaylist = useCallback((playlistName: string) => {
    if (selectedSongs.size > 0) {
      onAddToPlaylist(Array.from(selectedSongs), playlistName);
      setSelectedSongs(new Set()); // Clear selection after action
    }
  }, [selectedSongs, onAddToPlaylist]);

  const handleBulkRemoveFromPlaylist = useCallback(() => {
    if (selectedSongs.size > 0 && onRemoveFromPlaylist) {
      onRemoveFromPlaylist(Array.from(selectedSongs));
      setSelectedSongs(new Set()); // Clear selection after action
    }
  }, [selectedSongs, onRemoveFromPlaylist]);

  // Memoized song selection handler
  const handleSongSelect = useCallback((song: Song) => {
    onSongSelect(song);
  }, [onSongSelect]);

  // Memoized search handler with debouncing
  // Search handled inline via localSearchQuery effect

  // Provide drag payload: if multiple selected, drag all; else drag the single item
  const handleDragStart = useCallback((e: React.DragEvent, songIdsFallback: string[]) => {
    const ids = selectedSongs.size > 0 ? Array.from(selectedSongs) : songIdsFallback;
    dragSelectionRef.current = ids;
    setIsDragging(true);
    setIsReorderDragging(true);
    const payload = { type: 'songs', songIds: ids, count: ids.length };
    e.dataTransfer.setData('application/json', JSON.stringify(payload));
    e.dataTransfer.setData('text/plain', JSON.stringify(payload));
    e.dataTransfer.effectAllowed = 'copyMove';

    // Create a custom drag image with count badge when dragging multiple
    try {
      const count = ids.length;
      if (count >= 1) {
        // Build a lightweight preview element
        const preview = document.createElement('div');
        preview.style.position = 'fixed';
        preview.style.top = '-1000px';
        preview.style.left = '-1000px';
        preview.style.pointerEvents = 'none';
        preview.style.padding = '6px 10px';
        preview.style.borderRadius = '8px';
        preview.style.background = 'rgba(26, 32, 44, 0.95)'; // gray.900
        preview.style.color = '#E2E8F0'; // gray.200
        preview.style.fontSize = '12px';
        preview.style.fontWeight = '600';
        preview.style.display = 'inline-flex';
        preview.style.alignItems = 'center';
        preview.style.gap = '8px';
        preview.style.boxShadow = '0 4px 12px rgba(0,0,0,0.5)';

        const dot = document.createElement('div');
        dot.style.background = '#3182CE'; // blue.500
        dot.style.color = 'white';
        dot.style.minWidth = '20px';
        dot.style.height = '20px';
        dot.style.borderRadius = '10px';
        dot.style.display = 'flex';
        dot.style.alignItems = 'center';
        dot.style.justifyContent = 'center';
        dot.style.fontSize = '12px';
        dot.style.fontWeight = '700';
        dot.textContent = String(count);

        const label = document.createElement('div');
        label.textContent = count === 1 ? 'song' : 'songs';

        preview.appendChild(dot);
        preview.appendChild(label);
        document.body.appendChild(preview);
        dragPreviewRef.current = preview;
        // Offset so the cursor isn't on top of the preview
        e.dataTransfer.setDragImage(preview, 10, 10);
      }
    } catch {}
  }, [selectedSongs]);

  const handleDragEnd = useCallback(() => {
    setIsDragging(false);
    setIsReorderDragging(false);
    setEndDropHover(false);
    setDragHoverIndex(null);
    dragSelectionRef.current = null;
    // Cleanup drag preview element
    if (dragPreviewRef.current && dragPreviewRef.current.parentNode) {
      try { dragPreviewRef.current.parentNode.removeChild(dragPreviewRef.current); } catch {}
    }
    dragPreviewRef.current = null;
  }, []);

  // Virtualizer for large lists
  const rowVirtualizer = useVirtualizer({
    count: songs.length,
    getScrollElement: () => scrollContainerRef.current,
    estimateSize: () => 64,
    overscan: 8
  });

  // Use total playlist duration if available, otherwise calculate from current songs
  const totalDuration = useMemo(() => {
    if (totalPlaylistDuration) {
      return totalPlaylistDuration;
    }
    // Only calculate if we have songs and no total duration provided
    if (songs.length === 0) return '';
    
    // Fallback to calculating from current songs
    const totalSeconds = songs.reduce((total, song) => {
      if (!song.totalTime) return total;
      const seconds = Math.floor(Number(song.totalTime) / (song.totalTime.length > 4 ? 1000 : 1));
      return total + seconds;
    }, 0);
    return formatTotalDuration(totalSeconds);
  }, [songs, totalPlaylistDuration]);

  // Memoized playlist options for bulk actions
  // Playlist options built directly in the modal

  // Handle debounced search
  useEffect(() => {
    if (debouncedSearchQuery !== searchQuery) {
      onSearch(debouncedSearchQuery);
    }
  }, [debouncedSearchQuery, searchQuery, onSearch]);

  // Intersection Observer for infinite scroll - optimized
  useEffect(() => {
    if (loadingRef.current) {
      observerRef.current = new IntersectionObserver(
        (entries) => {
          // Use current values from refs to avoid stale closure
          if (entries[0].isIntersecting && hasMoreRef.current && !loadingRef_state.current && !isTriggeringRef.current) {
            isTriggeringRef.current = true;
            // Use requestAnimationFrame for better performance
            requestAnimationFrame(() => {
              onLoadMoreRef.current();
            });
            // Reset the flag after a short delay to prevent multiple triggers
            timeoutRef.current = setTimeout(() => {
              isTriggeringRef.current = false;
            }, 100);
          }
        },
        { 
          threshold: 0.1,
          rootMargin: '100px' // Start loading when 100px away from the bottom
        }
      );

      observerRef.current.observe(loadingRef.current);
    }

    return () => {
      if (observerRef.current) {
        observerRef.current.disconnect();
      }
      if (timeoutRef.current) {
        clearTimeout(timeoutRef.current);
      }
    };
  }, []); // Remove dependencies to prevent recreation

  return (
    <Flex direction="column" height="100%">
      {/* Global drag badge for selected count */}
      {isDragging && (
        <Box position="fixed" top={3} right={3} zIndex={2000} bg="blue.600" color="white" px={3} py={1} borderRadius="md" boxShadow="lg">
          Dragging {dragSelectionRef.current?.length || 0} song{(dragSelectionRef.current?.length || 0) === 1 ? '' : 's'}
        </Box>
      )}
      {/* Sticky Header */}
      <Box
        position="sticky"
        top={0}
        bg="gray.900"
        zIndex={1}
        pb={4}
      >
        {/* Search Bar */}
        <InputGroup mb={4}>
          <InputLeftElement pointerEvents="none">
            <Search2Icon color="gray.300" />
          </InputLeftElement>
          <Input
            placeholder="Search songs by title, artist, album, or genre..."
            value={localSearchQuery}
            onChange={(e: React.ChangeEvent<HTMLInputElement>) => setLocalSearchQuery(e.target.value)}
            bg="gray.800"
            borderColor="gray.600"
            _hover={{ borderColor: "gray.500" }}
            _focus={{ borderColor: "blue.300", boxShadow: "0 0 0 1px var(--chakra-colors-blue-300)" }}
            autoFocus
          />
        </InputGroup>

        {/* Bulk Actions Toolbar */}
        <Flex justify="space-between" align="center" p={2} bg="gray.800" borderRadius="md">
          <HStack spacing={4}>
            <Checkbox
              isChecked={selectedSongs.size === songs.length && songs.length > 0}
              isIndeterminate={selectedSongs.size > 0 && selectedSongs.size < songs.length}
              onChange={toggleSelectAll}
              colorScheme="blue"
              sx={{
                '& > span:first-of-type': {
                  opacity: 1,
                  border: '2px solid',
                  borderColor: 'gray.500'
                }
              }}
            >
              {selectedSongs.size === 0 
                ? "Select All" 
                : `Selected ${selectedSongs.size} song${selectedSongs.size === 1 ? '' : 's'}`}
            </Checkbox>
            <Text color="gray.400" fontSize="sm">
              {isSwitchingPlaylist ? (
                <>
                  0 of 0 songs • 
                  <Text as="span" color="blue.400" ml={1}>
                    Switching playlist...
                  </Text>
                </>
              ) : (
                <>
                  {songs.length} of {totalSongs} songs • {totalDuration}
                  {hasMore && songs.length > 0 && (
                    <Text as="span" color="blue.400" ml={2}>
                      • Scroll for more
                    </Text>
                  )}
                </>
              )}
            </Text>
          </HStack>
          
          {selectedSongs.size > 0 && (
            <HStack spacing={2}>
              <Button
                size="sm"
                colorScheme="blue"
                onClick={onPlaylistModalOpen}
              >
                Add to Playlist...
              </Button>
              {currentPlaylist !== "All Songs" && onRemoveFromPlaylist && (
                <Button
                  size="sm"
                  variant="outline"
                  colorScheme="red"
                  onClick={() => {
                    handleBulkRemoveFromPlaylist();
                  }}
                >
                  Remove from {currentPlaylist}
                </Button>
              )}
            </HStack>
          )}
        </Flex>
      </Box>

      {/* Scrollable Song List (virtualized) */}
      <Box 
        ref={scrollContainerRef}
        flex={1} 
        overflowY="auto" 
        mt={2} 
        id="song-list-container"
        sx={{
          scrollbarColor: 'var(--chakra-colors-gray-700) var(--chakra-colors-gray-900)',
          scrollbarWidth: 'thin',
          '&::-webkit-scrollbar': {
            width: '8px',
            height: '8px',
            backgroundColor: 'var(--chakra-colors-gray-900)'
          },
          '&::-webkit-scrollbar-thumb': {
            backgroundColor: 'var(--chakra-colors-gray-700)',
            borderRadius: '8px',
          },
          '&::-webkit-scrollbar-thumb:hover': {
            backgroundColor: 'var(--chakra-colors-gray-600)'
          },
          '&::-webkit-scrollbar-track': {
            backgroundColor: 'var(--chakra-colors-gray-900)'
          }
        }}
      >
        <Box position="relative" height={`${rowVirtualizer.getTotalSize()}px`}>
          <Box onDragEnd={handleDragEnd}>
            {rowVirtualizer.getVirtualItems().map((virtualRow: VirtualItem) => {
              const index = virtualRow.index;
              const song = songs[index];
              const allowReorder = Boolean(onReorder && currentPlaylist);
              return (
                <Box
                  key={song ? song.id : index}
                  position="absolute"
                  top={0}
                  left={0}
                  right={0}
                  transform={`translateY(${virtualRow.start}px)`}
                >
                  {song && (
                    <SongItem
                      song={song}
                      isSelected={selectedSongs.has(song.id)}
                      isHighlighted={selectedSongId === song.id}
                      onSelect={handleSongSelect}
                      onToggleSelection={toggleSelection}
                      showCheckbox={selectedSongs.size > 0 || depth === 0}
                      index={index}
                      onCheckboxToggle={handleCheckboxToggle}
                      onPlaySong={onPlaySong}
                      showDropIndicatorTop={dragHoverIndex === index}
                      onDragStart={handleDragStart}
                      onRowDragOver={allowReorder ? ((e: React.DragEvent) => {
                        if (!onReorder || !currentPlaylist) return;
                        e.preventDefault();
                        setDragHoverIndex(index);
                      }) : undefined}
                      onRowDrop={allowReorder ? (async (e: React.DragEvent) => {
                        if (!onReorder || !currentPlaylist) return;
                        e.preventDefault();
                        const fromId = e.dataTransfer.getData('text/song-id');
                        const multiJson = e.dataTransfer.getData('application/json');
                        let multiIds: string[] | null = null;
                        if (multiJson) {
                          try {
                            const parsed = JSON.parse(multiJson);
                            if (parsed && parsed.type === 'songs' && Array.isArray(parsed.songIds)) {
                              multiIds = parsed.songIds as string[];
                            }
                          } catch {}
                        }
                        if (!fromId && !multiIds) return;
                        const toId = songs[index]?.id;
                        if (!toId) return;
                        if (multiIds && multiIds.length > 0) {
                          await api.moveTracksInPlaylist(currentPlaylist, multiIds, toId);
                        } else {
                          await api.moveTrackInPlaylist(currentPlaylist, fromId!, toId);
                        }
                        await onReorder(songs.map(s => s.id));
                        setDragHoverIndex(null);
                        setIsReorderDragging(false);
                      }) : undefined}
                      onRowDragStartCapture={allowReorder ? ((e: React.DragEvent) => {
                        if (!currentPlaylist) return;
                        e.dataTransfer.setData('text/song-id', song.id);
                        try { e.dataTransfer.effectAllowed = 'move'; } catch {}
                        try { e.dataTransfer.dropEffect = 'move'; } catch {}
                        setIsReorderDragging(true);
                      }) : undefined}
                    />
                  )}
                </Box>
              );
            })}
          </Box>
        </Box>

          {/* Drop zone to move item to end of playlist */}
          {onReorder && currentPlaylist && selectedSongs.size === 0 && isReorderDragging && (
            <Box
              onDragOver={(e: React.DragEvent) => {
                e.preventDefault();
                setDragHoverIndex(null);
                setEndDropHover(true);
                try { e.dataTransfer.dropEffect = 'move'; } catch {}
              }}
              onDragLeave={() => setEndDropHover(false)}
              onDrop={async (e: React.DragEvent) => {
                e.preventDefault();
                const fromId = e.dataTransfer.getData('text/song-id');
                const multiJson = e.dataTransfer.getData('application/json');
                let multiIds: string[] | null = null;
                if (multiJson) {
                  try {
                    const parsed = JSON.parse(multiJson);
                    if (parsed && parsed.type === 'songs' && Array.isArray(parsed.songIds)) {
                      multiIds = parsed.songIds as string[];
                    }
                  } catch {}
                }
                if (!fromId && !multiIds) return;
                // Move to end: omit toId
                if (multiIds && multiIds.length > 0) {
                  await api.moveTracksInPlaylist(currentPlaylist, multiIds);
                } else {
                  await api.moveTrackInPlaylist(currentPlaylist, fromId!);
                }
                await onReorder(songs.map(s => s.id));
                setEndDropHover(false);
                setIsReorderDragging(false);
              }}
              onDragEnd={handleDragEnd}
              position="relative"
              height="28px"
              mt={1}
            >
              {endDropHover && (
                <Box position="absolute" top="50%" left={0} right={0} height="2px" bg="blue.400" />
              )}
            </Box>
          )}
          
          {/* Loading indicator for infinite scroll or playlist switching */}
          {(loading || isSwitchingPlaylist) && (
            <Flex justify="center" align="center" p={6} key="loading-spinner" gap={3}>
              <Spinner size="md" color="blue.400" />
              <Text color="gray.400" fontSize="sm">
                {isSwitchingPlaylist ? 'Switching playlist...' : 'Loading more songs...'}
              </Text>
            </Flex>
          )}
          
          {/* Intersection observer target */}
          <div ref={loadingRef} style={{ height: '20px' }} key="intersection-target" />
          
          {/* Loading more indicator (subtle) */}
          {!loading && hasMore && songs.length > 0 && (
            <Flex justify="center" p={3} key="loading-more-indicator">
              <Text color="gray.600" fontSize="xs">
                Scroll for more songs
              </Text>
            </Flex>
          )}
          
          {/* End of results message */}
          {!hasMore && songs.length > 0 && (
            <Flex justify="center" p={4} key="end-message">
              <Text color="gray.500" fontSize="sm">
                No more songs to load
              </Text>
            </Flex>
          )}
          
          {/* No results message */}
          {!loading && !isSwitchingPlaylist && songs.length === 0 && (
            <Flex justify="center" p={8} key="no-results" direction="column" align="center" gap={3}>
              <Text color="gray.500">
                {searchQuery ? 'No songs found matching your search' : 'No songs available'}
              </Text>
            </Flex>
          )}
        
      </Box>

      {/* Playlist Selection Modal */}
      <PlaylistSelectionModal
        isOpen={isPlaylistModalOpen}
        onClose={onPlaylistModalClose}
        playlists={playlists}
        onPlaylistSelect={handleBulkAddToPlaylist}
        selectedSongCount={selectedSongs.size}
      />
    </Flex>
  );
}); 