'use client';

import { useState, useEffect, useRef, useCallback, useMemo } from 'react';
import { FixedSizeGrid } from 'react-window';
import { Card, CardContent } from '@/components/ui/card';
import { StarRating } from '@/components/star-rating';
import { Film, Image as ImageIcon, HardDrive, Search, Bookmark } from 'lucide-react';
import { Input } from '@/components/ui/input';

interface MediaItem {
  id: number;
  title: string;
  path: string;
  size: number;
  thumbnail: string;
  type: string;
  bookmark_count: number;
  avg_rating: number;
  star_count: number;
}

interface InfiniteVirtualGridProps {
  type: 'video' | 'photo' | 'bookmark';
  onItemClick: (item: MediaItem, index?: number) => void;
  onBookmark: (id: number) => Promise<void>;
  onUnbookmark: (id: number) => Promise<void>;
  onRate: (id: number, rating: number) => Promise<void>;
  onDataUpdate?: (items: MediaItem[]) => void;
}

const ITEM_HEIGHT = 220;
const ITEMS_PER_BATCH = 50;
const BUFFER_SIZE = 200;

export default function InfiniteVirtualGrid({ 
  type, 
  onItemClick, 
  onBookmark, 
  onUnbookmark, 
  onRate,
  onDataUpdate
}: InfiniteVirtualGridProps) {
  const [totalItems, setTotalItems] = useState(0);
  const [searchTerm, setSearchTerm] = useState('');
  const [containerWidth, setContainerWidth] = useState(0);
  const [isLoadingInitial, setIsLoadingInitial] = useState(true);
  
  const loadingRef = useRef<Set<number>>(new Set());
  const dataCacheRef = useRef<Map<number, MediaItem[]>>(new Map());
  const containerRef = useRef<HTMLDivElement>(null);
  const gridRef = useRef<any>(null);

  const formatFileSize = useCallback((bytes: number) => {
    if (bytes === 0) return '0 Bytes';
    const k = 1024;
    const sizes = ['Bytes', 'KB', 'MB', 'GB'];
    const i = Math.floor(Math.log(bytes) / Math.log(k));
    return parseFloat((bytes / Math.pow(k, i)).toFixed(2)) + ' ' + sizes[i];
  }, []);

  const formatFilePath = useCallback((path: string) => {
    if (!path) return '';
    
    const lastSlashIndex = path.lastIndexOf('/');
    const lastBackslashIndex = path.lastIndexOf('\\');
    const lastSeparatorIndex = Math.max(lastSlashIndex, lastBackslashIndex);
    
    if (lastSeparatorIndex === -1) {
      return path;
    }
    
    const directory = path.substring(0, lastSeparatorIndex);
    const filename = path.substring(lastSeparatorIndex + 1);
    
    if (directory.length <= 40) {
      return `${directory}/${filename}`;
    }
    
    const maxDirLength = 35;
    const startLength = Math.floor(maxDirLength / 2);
    const endLength = maxDirLength - startLength - 3;
    
    const truncatedDir = directory.length > maxDirLength 
      ? `${directory.substring(0, startLength)}...${directory.substring(directory.length - endLength)}`
      : directory;
    
    return `${truncatedDir}/${filename}`;
  }, []);

  const getColumnCount = useCallback(() => {
    if (containerWidth === 0) return 6;
    if (containerWidth < 640) return 2;
    if (containerWidth < 768) return 3;
    if (containerWidth < 1024) return 4;
    if (containerWidth < 1280) return 5;
    if (containerWidth < 1536) return 6;
    return 7;
  }, [containerWidth]);

  const getColumnWidth = useCallback(() => {
    const cols = getColumnCount();
    const availableWidth = containerWidth - 32;
    const gapWidth = (cols - 1) * 16;
    return Math.floor((availableWidth - gapWidth) / cols);
  }, [containerWidth, getColumnCount]);

  const rowCount = useMemo(() => {
    return Math.ceil(totalItems / getColumnCount());
  }, [totalItems, getColumnCount]);

  const fetchItems = useCallback(async (startIndex: number, endIndex: number) => {
    const batchStart = Math.floor(startIndex / ITEMS_PER_BATCH) * ITEMS_PER_BATCH;
    const batchKey = Math.floor(startIndex / ITEMS_PER_BATCH);

    if (loadingRef.current.has(batchKey) || dataCacheRef.current.has(batchKey)) {
      return;
    }

    loadingRef.current.add(batchKey);
    
    try {
      const limit = Math.min(ITEMS_PER_BATCH, totalItems - batchStart);
      if (limit <= 0) return;

      const params = new URLSearchParams({
        limit: limit.toString(),
        offset: batchStart.toString(),
        ...(searchTerm && { search: searchTerm })
      });

      const endpoint = type === 'bookmark' ? 'bookmarks' : `${type}s`;
      const response = await fetch(`/api/${endpoint}?${params}`);
      const data = await response.json();

      const itemsKey = type === 'bookmark' ? 'bookmarks' : `${type}s`;
      const items = data[itemsKey] || [];

      dataCacheRef.current.set(batchKey, items);

    } catch (error) {
      console.error(`Error fetching ${type}s:`, error);
    } finally {
      loadingRef.current.delete(batchKey);
    }
  }, [type, searchTerm, totalItems]);

  const fetchTotalCount = useCallback(async () => {
    try {
      const endpoint = type === 'bookmark' ? 'bookmarks' : `${type}s`;
      
      const params = new URLSearchParams({
        limit: '50',
        offset: '0',
        ...(searchTerm && { search: searchTerm })
      });

      const response = await fetch(`/api/${endpoint}?${params}`);
      const data = await response.json();
      
      const itemsKey = type === 'bookmark' ? 'bookmarks' : `${type}s`;
      const items = data[itemsKey] || [];
      
      if (items.length > 0) {
        dataCacheRef.current.set(0, items);
      }
      
      setTotalItems(data.pagination.total || 0);
      setIsLoadingInitial(false);
    } catch (error) {
      console.error(`Error fetching total count for ${type}:`, error);
      setTotalItems(0);
      setIsLoadingInitial(false);
    }
  }, [type, searchTerm]);

  useEffect(() => {
    dataCacheRef.current.clear();
    loadingRef.current.clear();
    setTotalItems(0);
    setIsLoadingInitial(true);
    fetchTotalCount();
  }, [type, searchTerm, fetchTotalCount]);

  useEffect(() => {
    const updateWidth = () => {
      if (containerRef.current) {
        const width = containerRef.current.offsetWidth;
        setContainerWidth(width);
      }
    };

    // Use ResizeObserver for more reliable width detection
    const resizeObserver = new ResizeObserver(entries => {
      if (entries[0]) {
        setContainerWidth(entries[0].contentRect.width);
      }
    });

    if (containerRef.current) {
      resizeObserver.observe(containerRef.current);
      updateWidth(); // Initial measurement
    }

    // Window resize fallback
    const handleResize = () => {
      updateWidth();
    };
    window.addEventListener('resize', handleResize);

    // Fallback to manual measurement if ResizeObserver not available
    const fallbackUpdate = () => {
      setTimeout(updateWidth, 100);
    };
    fallbackUpdate();

    return () => {
      resizeObserver.disconnect();
      window.removeEventListener('resize', handleResize);
    };
  }, []);

  // Aggressive width detection fallback
  useEffect(() => {
    const aggressiveWidthCheck = () => {
      // Try to find any suitable container
      const containers = [
        containerRef.current,
        document.querySelector('.flex-1') as HTMLElement,
        document.querySelector('.max-w-7xl') as HTMLElement,
        document.querySelector('.w-full') as HTMLElement
      ].filter(Boolean);
      
      for (const container of containers) {
        if (container) {
          const width = (container as HTMLElement).offsetWidth || (container as HTMLElement).clientWidth;
          if (width > 0) {
            setContainerWidth(width);
            return;
          }
        }
      }
      
      // As a last resort, use window width minus some padding
      const fallbackWidth = Math.max(window.innerWidth - 64, 320);
      setContainerWidth(fallbackWidth);
    };

    // Try multiple times with increasing delays
    aggressiveWidthCheck();
    const timeouts = [
      setTimeout(aggressiveWidthCheck, 50),
      setTimeout(aggressiveWidthCheck, 100),
      setTimeout(aggressiveWidthCheck, 500)
    ];

    return () => {
      timeouts.forEach(timeout => clearTimeout(timeout));
    };
  }, []);

  const getItemData = useCallback((index: number): MediaItem | null => {
    if (index >= totalItems) return null;
    
    const batchKey = Math.floor(index / ITEMS_PER_BATCH);
    const batchItems = dataCacheRef.current.get(batchKey);
    
    if (!batchItems) {
      return null;
    }
    
    const itemIndex = index % ITEMS_PER_BATCH;
    return batchItems[itemIndex] || null;
  }, [totalItems]);

  const handleItemsRendered = useCallback((params: any) => {
    const { visibleRowStartIndex, visibleRowStopIndex } = params;
    
    console.log('onItemsRendered triggered:', { visibleRowStartIndex, visibleRowStopIndex, totalItems, columnCount: getColumnCount() });
    
    if (typeof visibleRowStartIndex !== 'number' || typeof visibleRowStopIndex !== 'number') {
      console.log('Invalid indices received');
      return;
    }
    
    if (totalItems === 0) {
      console.log('No total items');
      return;
    }
    
    const columnCount = getColumnCount();
    
    // Convert row indices to absolute item indices
    const startIndex = visibleRowStartIndex * columnCount;
    const endIndex = Math.min((visibleRowStopIndex + 1) * columnCount - 1, totalItems - 1);
    
    console.log('Calculated indices:', { startIndex, endIndex, columnCount });
    
    // Check what batches we need to load
    const startBatch = Math.floor(startIndex / ITEMS_PER_BATCH);
    const endBatch = Math.floor(endIndex / ITEMS_PER_BATCH);
    
    console.log('Batch range needed:', { startBatch, endBatch });
    
    // Load missing batches
    let loadedAny = false;
    for (let batch = startBatch; batch <= endBatch; batch++) {
      const batchStart = batch * ITEMS_PER_BATCH;
      const batchEnd = Math.min((batch + 1) * ITEMS_PER_BATCH, totalItems);
      
      if (!dataCacheRef.current.has(batch) && !loadingRef.current.has(batch)) {
        console.log(`Loading batch ${batch}: ${batchStart}-${batchEnd}`);
        fetchItems(batchStart, batchEnd);
        loadedAny = true;
      }
    }
    
    // Also check if we need to load more for infinite scroll
    if (!loadedAny) {
      const lastLoadedBatch = Math.max(...Array.from(dataCacheRef.current.keys()), -1);
      const nextBatch = lastLoadedBatch + 1;
      const nextBatchStart = nextBatch * ITEMS_PER_BATCH;
      
      if (nextBatchStart < totalItems && endIndex + BUFFER_SIZE >= nextBatchStart) {
        const batchEnd = Math.min(nextBatchStart + ITEMS_PER_BATCH, totalItems);
        console.log(`Loading next batch for infinite scroll ${nextBatch}: ${nextBatchStart}-${batchEnd}`);
        fetchItems(nextBatchStart, batchEnd);
      }
    }
    
    // Collect all available items and notify parent
    if (onDataUpdate) {
      const allItems: MediaItem[] = [];
      const sortedKeys = Array.from(dataCacheRef.current.keys()).sort((a, b) => a - b);
      
      for (const batchKey of sortedKeys) {
        const items = dataCacheRef.current.get(batchKey);
        if (items) {
          allItems.push(...items);
        }
      }
      
      if (allItems.length > 0) {
        onDataUpdate(allItems);
      }
    }
  }, [totalItems, fetchItems, getColumnCount]);

  const Cell = ({ columnIndex, rowIndex, style }: any) => {
    const columnCount = getColumnCount();
    const index = rowIndex * columnCount + columnIndex;
    
    if (index >= totalItems) return null;
    
    const item = getItemData(index);
    
    if (!item) {
      return (
        <div style={style} className="p-2">
          <Card className="h-full animate-pulse bg-muted/50">
            <div className={`${type === 'video' ? 'aspect-video' : 'aspect-square'} bg-muted`} />
            <CardContent className="p-3">
              <div className="h-4 bg-muted rounded mb-2" />
              <div className="h-3 bg-muted rounded mb-1" />
            </CardContent>
          </Card>
        </div>
      );
    }

    return (
      <div style={style} className="p-2">
        <Card 
          className="group hover:shadow-lg transition-all duration-300 hover:-translate-y-1 cursor-pointer border-border overflow-hidden h-full"
          onClick={() => onItemClick(item, index)}
        >
          <div className="relative overflow-hidden bg-muted aspect-video">
            <img
              src={item.thumbnail || (type === 'video' ? "/placeholder-video.svg" : "/placeholder-photo.svg")}
              alt={item.title}
              className="w-full h-full object-cover transition-transform duration-500 group-hover:scale-105"
              onError={(e) => {
                (e.target as HTMLImageElement).src = type === 'video' ? "/placeholder-video.svg" : "/placeholder-photo.svg";
              }}
            />
            <div className="absolute inset-0 bg-gradient-to-t from-black/60 via-transparent to-transparent opacity-0 group-hover:opacity-100 transition-opacity duration-300" />
            
            <div className="absolute inset-0 flex items-center justify-center opacity-0 group-hover:opacity-100 transition-opacity duration-300">
              <div className="w-10 h-10 bg-white/90 backdrop-blur-sm rounded-full flex items-center justify-center shadow-lg">
                {type === 'video' ? 
                  <Film className="h-5 w-5 text-foreground" /> : 
                  <ImageIcon className="h-5 w-5 text-foreground" />
                }
              </div>
            </div>

            <div className="absolute top-2 right-2">
              <div className="bg-black/70 backdrop-blur-sm rounded-full px-2 py-1">
                {type === 'video' ? 
                  <Film className="h-3 w-3 text-white" /> : 
                  <ImageIcon className="h-3 w-3 text-white" />
                }
              </div>
            </div>
          </div>
          
          <CardContent className="p-2.5">
            <div className="flex items-start justify-between min-h-[2rem]">
              <div className="flex-1 min-w-0">
                <h3 className="font-medium text-foreground text-xs line-clamp-2 group-hover:text-primary transition-colors leading-tight">
                  {item.title || item.path.split('/').pop()}
                </h3>
                
                {(item.avg_rating > 0 || item.star_count > 0) && (
                  <div className="mt-0.5">
                    <StarRating 
                      rating={item.avg_rating || 0} 
                      count={item.star_count}
                      size="xs"
                      showCount={false}
                    />
                  </div>
                )}
              </div>
              
              <div className="flex gap-1 ml-1 flex-shrink-0">
                {type === 'video' && item.bookmark_count > 0 && (
                  <div className="text-xs text-yellow-500">
                    <Bookmark className="h-2.5 w-2.5 fill-yellow-500" />
                  </div>
                )}
              </div>
            </div>
            
            <div className="mt-1 space-y-0.5">
              <div className="flex items-center justify-between text-xs text-muted-foreground">
                <div className="flex items-center gap-1">
                  <HardDrive className="h-2.5 w-2.5" />
                  <span>{formatFileSize(item.size)}</span>
                </div>
                {type === 'video' && item.bookmark_count > 0 && (
                  <span className="text-xs text-muted-foreground">
                    {item.bookmark_count}
                  </span>
                )}
              </div>
              
              <p 
                className="text-xs text-muted-foreground line-clamp-1 cursor-help hover:text-foreground transition-colors"
                title={item.path}
              >
                {formatFilePath(item.path)}
              </p>
            </div>
          </CardContent>
        </Card>
      </div>
    );
  };

  const getAvailableHeight = useCallback(() => {
    if (typeof window === 'undefined') return 600;
    const headerHeight = 180;
    const bottomPadding = 20;
    return Math.max(window.innerHeight - headerHeight - bottomPadding, 400);
  }, []);

  if (isLoadingInitial) {
    return (
      <div className="h-screen flex flex-col overflow-hidden">
        <div className="flex-1 flex items-center justify-center">
          <div className="text-center">
            <div className="w-16 h-16 bg-gradient-to-br from-primary to-primary/80 rounded-2xl flex items-center justify-center mx-auto mb-4 animate-pulse shadow-lg">
              {type === 'video' ? 
                <Film className="h-8 w-8 text-primary-foreground" /> : 
                <ImageIcon className="h-8 w-8 text-primary-foreground" />
              }
            </div>
            <p className="text-muted-foreground font-medium">Loading {type}s...</p>
          </div>
        </div>
      </div>
    );
  }

  if (totalItems === 0) {
    return (
      <div className="h-screen flex flex-col overflow-hidden">
        <div ref={containerRef} className="flex-1 flex flex-col max-w-7xl mx-auto w-full overflow-hidden">
          <div className="flex-shrink-0 p-6 pb-4">
            <div className="flex items-center gap-4 mb-4">
              <div className={`w-12 h-12 bg-gradient-to-br rounded-xl flex items-center justify-center shadow-lg ${
                type === 'video' ? 'from-red-500 to-red-600' : 
                type === 'photo' ? 'from-green-500 to-green-600' :
                'from-blue-500 to-blue-600'
              }`}>
                {type === 'video' ? 
                  <Film className="h-6 w-6 text-white" /> : 
                  type === 'photo' ? 
                  <ImageIcon className="h-6 w-6 text-white" /> :
                  <Bookmark className="h-6 w-6 text-white" />
                }
              </div>
              <div>
                <h1 className="text-3xl font-bold text-foreground tracking-tight capitalize">
                  {type === 'bookmark' ? 'Bookmarked Items' : `${type}s`}
                </h1>
                <p className="text-muted-foreground">
                  0 {type === 'bookmark' ? 'item' : type}{type === 'bookmark' || type === 'photo' ? 's' : ''} in your library
                </p>
              </div>
            </div>

            <div className="relative max-w-md">
              <Search className="absolute left-3 top-1/2 transform -translate-y-1/2 h-4 w-4 text-muted-foreground" />
              <Input
                placeholder={`Search ${type}s...`}
                value={searchTerm}
                onChange={(e) => setSearchTerm(e.target.value)}
                className="pl-10 bg-background border-border"
              />
            </div>
          </div>

          <div className="flex-1 flex items-center justify-center">
            <div className="text-center max-w-sm">
              <div className="w-16 h-16 bg-muted rounded-2xl flex items-center justify-center mx-auto mb-4">
                <Search className="h-8 w-8 text-muted-foreground" />
              </div>
              <h3 className="text-xl font-semibold text-foreground mb-2">
                No {type === 'bookmark' ? 'bookmarked items' : `${type}s`} found
              </h3>
              <p className="text-muted-foreground">
                {searchTerm ? 'Try adjusting your search terms' : 
                 type === 'bookmark' ? 'Start bookmarking videos and photos to see them here' :
                 'Add media libraries and scan for content to get started'}
              </p>
            </div>
          </div>
        </div>
      </div>
    );
  }

  return (
    <div className="h-screen flex flex-col overflow-hidden">
      <div ref={containerRef} className="flex-1 flex flex-col max-w-7xl mx-auto w-full overflow-hidden">
        <div className="flex-shrink-0 p-6 pb-4">
          <div className="flex items-center gap-4 mb-4">
            <div className={`w-12 h-12 bg-gradient-to-br rounded-xl flex items-center justify-center shadow-lg ${
              type === 'video' ? 'from-red-500 to-red-600' : 
              type === 'photo' ? 'from-green-500 to-green-600' :
              'from-blue-500 to-blue-600'
            }`}>
              {type === 'video' ? 
                <Film className="h-6 w-6 text-white" /> : 
                type === 'photo' ? 
                <ImageIcon className="h-6 w-6 text-white" /> :
                <Bookmark className="h-6 w-6 text-white" />
              }
            </div>
            <div>
              <h1 className="text-3xl font-bold text-foreground tracking-tight capitalize">
                {type === 'bookmark' ? 'Bookmarked Items' : `${type}s`}
              </h1>
              <p className="text-muted-foreground">
                {totalItems.toLocaleString()} {type === 'bookmark' ? 'item' : type}{totalItems === 1 ? '' : 's'} in your library
              </p>
            </div>
          </div>

          <div className="relative max-w-md">
            <Search className="absolute left-3 top-1/2 transform -translate-y-1/2 h-4 w-4 text-muted-foreground" />
            <Input
              placeholder={`Search ${type}s...`}
              value={searchTerm}
              onChange={(e) => setSearchTerm(e.target.value)}
              className="pl-10 bg-background border-border"
            />
          </div>
        </div>

        <div ref={containerRef} className="flex-1 relative overflow-hidden">
          {containerWidth > 0 && (
            <FixedSizeGrid
              ref={gridRef}
              columnCount={getColumnCount()}
              columnWidth={getColumnWidth()}
              height={getAvailableHeight()}
              rowCount={rowCount}
              rowHeight={ITEM_HEIGHT}
              width={containerWidth}
              itemData={null}
              onItemsRendered={handleItemsRendered}
              overscanRowCount={5}
            >
              {Cell}
            </FixedSizeGrid>
          )}
          {containerWidth === 0 && (
            <div className="flex items-center justify-center h-full">
              <div className="animate-spin rounded-full h-8 w-8 border-b-2 border-primary"></div>
            </div>
          )}
        </div>
      </div>
    </div>
  );
}