"use client"

import React, { useState, useEffect, useRef, useCallback, useMemo } from 'react'
import { motion, AnimatePresence } from 'framer-motion'
import { cn } from '../../lib/utils'

// Virtual List Props
export interface VirtualListProps<T = any> {
  items: T[]
  height: number
  itemHeight?: number
  estimatedItemHeight?: number
  variableHeight?: boolean
  overscan?: number
  renderItem: (item: T, index: number) => React.ReactNode
  onScroll?: (scrollTop: number) => void
  className?: string
  // Infinite scrolling props
  hasNextPage?: boolean
  isLoadingNextPage?: boolean
  onLoadMore?: () => void | Promise<void>
  loadMoreThreshold?: number
  renderLoader?: () => React.ReactNode
  renderEndMessage?: () => React.ReactNode
  // Animation props
  enableAnimations?: boolean
  itemEnterAnimation?: {
    initial?: any
    animate?: any
    exit?: any
    transition?: any
  }
  listAnimation?: {
    initial?: any
    animate?: any 
    transition?: any
  }
  staggerDelay?: number
}

// Item bilgilerini saklamak için
interface ItemInfo {
  index: number
  height: number
  top: number
}

// Performans optimize edilmiş Virtual List Component
export function VirtualList<T = any>({
  items,
  height,
  itemHeight = 50,
  estimatedItemHeight = 50,
  variableHeight = false,
  overscan = 5,
  renderItem,
  onScroll,
  className,
  // Infinite scrolling props
  hasNextPage = false,
  isLoadingNextPage = false,
  onLoadMore,
  loadMoreThreshold = 500,
  renderLoader,
  renderEndMessage,
  // Animation props
  enableAnimations = false,
  itemEnterAnimation = {
    initial: { opacity: 0, y: 20 },
    animate: { opacity: 1, y: 0 },
    exit: { opacity: 0, y: -20 },
    transition: { duration: 0.2 }
  },
  listAnimation = {
    initial: { opacity: 0 },
    animate: { opacity: 1 },
    transition: { duration: 0.3 }
  },
  staggerDelay = 0.05
}: VirtualListProps<T>) {
  // State yönetimi
  const [scrollTop, setScrollTop] = useState(0)
  const [isScrolling, setIsScrolling] = useState(false)
  const [itemHeights, setItemHeights] = useState<Map<number, number>>(new Map())

  // Refs
  const containerRef = useRef<HTMLDivElement>(null)
  const scrollElementRef = useRef<HTMLDivElement>(null)
  const scrollTimeoutRef = useRef<NodeJS.Timeout | undefined>(undefined)
  const isScrollingTimeoutRef = useRef<NodeJS.Timeout | undefined>(undefined)

  // Container dimensions tracking
  const [containerDimensions, setContainerDimensions] = useState({ width: 0, height: 0 })
  
  useEffect(() => {
    if (!containerRef.current) return

    const resizeObserver = new ResizeObserver((entries) => {
      const entry = entries[0]
      if (entry) {
        setContainerDimensions({
          width: entry.contentRect.width,
          height: entry.contentRect.height
        })
      }
    })

    resizeObserver.observe(containerRef.current)
    return () => resizeObserver.disconnect()
  }, [])

  // Item pozisyonlarını hesapla
  const itemPositions = useMemo(() => {

    const positions: ItemInfo[] = []
    let currentTop = 0
    let currentLeft = 0

    for (let i = 0; i < items.length; i++) {
      const currentHeight = variableHeight 
        ? (itemHeights.get(i) || estimatedItemHeight)
        : itemHeight

      positions.push({
        index: i,
        height: currentHeight,
        top: currentTop
      })

      currentTop += currentHeight
    }

    return positions
  }, [
    items.length, 
    itemHeight, 
    estimatedItemHeight, 
    variableHeight, 
    itemHeights
  ])

  // Toplam içerik yüksekliği
  const totalHeight = useMemo(() => {
    let baseHeight = itemPositions.length > 0 
      ? itemPositions[itemPositions.length - 1].top + itemPositions[itemPositions.length - 1].height
      : 0

    // Infinite scrolling için ek yükseklik ekle
    if (hasNextPage && isLoadingNextPage) {
      baseHeight += 50 // Loader yüksekliği
    } else if (!hasNextPage && items.length > 0) {
      baseHeight += 40 // End message yüksekliği
    }

    return baseHeight
  }, [itemPositions, hasNextPage, isLoadingNextPage, items.length])

  // Görünür aralığı hesapla
  const visibleRange = useMemo(() => {
    const start = itemPositions.findIndex(item => item.top + item.height >= scrollTop)
    const end = itemPositions.findIndex(item => item.top > scrollTop + height)

    const actualStart = Math.max(0, start - overscan)
    const actualEnd = end === -1 
      ? Math.min(items.length - 1, start + Math.ceil(height / itemHeight) + overscan)
      : Math.min(items.length - 1, end + overscan)

    return {
      start: actualStart,
      end: actualEnd
    }
  }, [scrollTop, height, itemPositions, overscan, items.length, itemHeight])


  // Görünür itemlar
  const visibleItems = useMemo(() => {
    const result: Array<{ item: T; index: number; style: React.CSSProperties }> = []
    
    for (let i = visibleRange.start; i <= visibleRange.end; i++) {
      if (i >= 0 && i < items.length && itemPositions[i]) {
        const position = itemPositions[i]
        result.push({
          item: items[i],
          index: i,
          style: {
            position: 'absolute',
            top: position.top,
            left: 0,
            right: 0,
            height: variableHeight ? 'auto' : position.height,
            minHeight: variableHeight ? position.height : undefined
          }
        })
      }
    }

    return result
  }, [items, visibleRange, itemPositions, variableHeight])

  // Scroll handler
  const handleScroll = useCallback((e: React.UIEvent<HTMLDivElement>) => {
    const scrollTop = e.currentTarget.scrollTop
    const scrollHeight = e.currentTarget.scrollHeight
    const clientHeight = e.currentTarget.clientHeight
    
    setScrollTop(scrollTop)
    setIsScrolling(true)

    // Scroll callback
    if (onScroll) {
      onScroll(scrollTop)
    }

    // Infinite scrolling check
    if (
      hasNextPage &&
      !isLoadingNextPage &&
      onLoadMore &&
      scrollHeight - (scrollTop + clientHeight) <= loadMoreThreshold
    ) {
      onLoadMore()
    }

    // Scroll timeout'ını temizle ve yenisini ayarla
    if (scrollTimeoutRef.current) {
      clearTimeout(scrollTimeoutRef.current)
    }

    if (isScrollingTimeoutRef.current) {
      clearTimeout(isScrollingTimeoutRef.current)
    }

    // 150ms sonra scrolling'i false yap (performans için)
    isScrollingTimeoutRef.current = setTimeout(() => {
      setIsScrolling(false)
    }, 150)
  }, [onScroll, hasNextPage, isLoadingNextPage, onLoadMore, loadMoreThreshold])

  // Variable height için resize observer
  useEffect(() => {
    if (!variableHeight || !containerRef.current) return

    const resizeObserver = new ResizeObserver((entries) => {
      const newHeights = new Map(itemHeights)
      let hasChanges = false

      entries.forEach((entry) => {
        const element = entry.target as HTMLElement
        const indexAttr = element.getAttribute('data-index')
        
        if (indexAttr) {
          const index = parseInt(indexAttr, 10)
          const newHeight = entry.contentRect.height
          
          if (newHeights.get(index) !== newHeight) {
            newHeights.set(index, newHeight)
            hasChanges = true
          }
        }
      })

      if (hasChanges) {
        setItemHeights(newHeights)
      }
    })

    // Mevcut tüm item elementlerini observe et
    const itemElements = containerRef.current.querySelectorAll('[data-index]')
    itemElements.forEach(el => resizeObserver.observe(el))

    return () => resizeObserver.disconnect()
  }, [variableHeight, itemHeights, visibleItems])

  // Keyboard navigation desteği
  useEffect(() => {
    const handleKeyDown = (e: KeyboardEvent) => {
      if (!containerRef.current) return

      switch (e.key) {
        case 'ArrowUp':
          e.preventDefault()
          scrollElementRef.current?.scrollBy({ top: -itemHeight, behavior: 'smooth' })
          break
        case 'ArrowDown':
          e.preventDefault()
          scrollElementRef.current?.scrollBy({ top: itemHeight, behavior: 'smooth' })
          break
        case 'PageUp':
          e.preventDefault()
          scrollElementRef.current?.scrollBy({ top: -height, behavior: 'smooth' })
          break
        case 'PageDown':
          e.preventDefault()
          scrollElementRef.current?.scrollBy({ top: height, behavior: 'smooth' })
          break
        case 'Home':
          e.preventDefault()
          scrollElementRef.current?.scrollTo({ top: 0, behavior: 'smooth' })
          break
        case 'End':
          e.preventDefault()
          scrollElementRef.current?.scrollTo({ top: totalHeight, behavior: 'smooth' })
          break
      }
    }

    const container = containerRef.current
    if (container) {
      container.addEventListener('keydown', handleKeyDown)
      return () => container.removeEventListener('keydown', handleKeyDown)
    }
  }, [itemHeight, height, totalHeight])

  const ContainerComponent = enableAnimations ? motion.div : 'div'
  const ContentComponent = enableAnimations ? motion.div : 'div'
  const ItemComponent = enableAnimations ? motion.div : 'div'

  return (
    <ContainerComponent
      ref={containerRef}
      className={cn(
        "relative overflow-hidden border rounded-lg bg-background focus:outline-none focus:ring-2 focus:ring-ring",
        className
      )}
      style={{ height }}
      tabIndex={0}
      role="listbox"
      aria-label={`Virtual list with ${items.length} items`}
      {...(enableAnimations && listAnimation)}
    >
      <div
        ref={scrollElementRef}
        className="h-full overflow-auto scrollbar-thin scrollbar-thumb-muted scrollbar-track-transparent"
        onScroll={handleScroll}
      >
        <ContentComponent
          style={{
            height: totalHeight,
            position: 'relative'
          }}
          {...(enableAnimations && {
            initial: { opacity: 0 },
            animate: { opacity: 1 },
            transition: { duration: 0.2 }
          })}
        >
          <AnimatePresence mode="popLayout">
            {visibleItems.map(({ item, index, style }, itemIndex) => (
              <ItemComponent
                key={`${index}-${JSON.stringify(item)}`}
                data-index={index}
                style={style}
                role="option"
                aria-selected="false"
                className="outline-none"
                {...(enableAnimations && {
                  ...itemEnterAnimation,
                  transition: {
                    ...itemEnterAnimation.transition,
                    delay: itemIndex * staggerDelay
                  }
                })}
              >
                {renderItem(item, index)}
              </ItemComponent>
            ))}
          </AnimatePresence>

          {/* Infinite scrolling loader */}
          {hasNextPage && isLoadingNextPage && (
            <motion.div 
              style={{
                position: 'absolute',
                top: totalHeight,
                left: 0,
                right: 0,
                minHeight: 50
              }}
              className="flex items-center justify-center py-4"
              initial={{ opacity: 0, y: 20 }}
              animate={{ opacity: 1, y: 0 }}
              exit={{ opacity: 0, y: -20 }}
              transition={{ duration: 0.3 }}
            >
              {renderLoader ? renderLoader() : (
                <div className="flex items-center gap-2 text-muted-foreground">
                  <motion.div 
                    className="rounded-full h-4 w-4 border-2 border-primary border-t-transparent"
                    animate={{ rotate: 360 }}
                    transition={{ duration: 1, repeat: Infinity, ease: "linear" }}
                  />
                  <span className="text-sm">Loading more...</span>
                </div>
              )}
            </motion.div>
          )}

          {/* End message */}
          {!hasNextPage && items.length > 0 && (
            <motion.div 
              style={{
                position: 'absolute',
                top: totalHeight,
                left: 0,
                right: 0,
                minHeight: 40
              }}
              className="flex items-center justify-center py-3"
              initial={{ opacity: 0, scale: 0.9 }}
              animate={{ opacity: 1, scale: 1 }}
              transition={{ duration: 0.2 }}
            >
              {renderEndMessage ? renderEndMessage() : (
                <div className="text-sm text-muted-foreground">
                  No more items to load
                </div>
              )}
            </motion.div>
          )}
        </ContentComponent>
      </div>

      {/* Loading indicator for scrolling */}
      <AnimatePresence>
        {isScrolling && (
          <motion.div 
            className="absolute top-2 right-2 bg-muted/80 text-muted-foreground px-2 py-1 rounded text-xs"
            initial={{ opacity: 0, scale: 0.8 }}
            animate={{ opacity: 1, scale: 1 }}
            exit={{ opacity: 0, scale: 0.8 }}
            transition={{ duration: 0.15 }}
          >
            Scrolling...
          </motion.div>
        )}
      </AnimatePresence>

      {/* Scroll position indicator */}
      {items.length > 100 && (
        <motion.div 
          className="absolute bottom-2 right-2 bg-muted/80 text-muted-foreground px-2 py-1 rounded text-xs"
          initial={{ opacity: 0, y: 10 }}
          animate={{ opacity: 1, y: 0 }}
          transition={{ duration: 0.2, delay: 0.5 }}
        >
          {Math.round((scrollTop / Math.max(totalHeight - height, 1)) * 100)}%
        </motion.div>
      )}

    </ContainerComponent>
  )
}


// Utility hook for virtual list state management
export function useVirtualList<T>(
  items: T[],
  initialConfig: Partial<VirtualListProps<T>> = {}
) {
  const [config, setConfig] = useState(initialConfig)
  const [selectedItems, setSelectedItems] = useState<Set<number>>(new Set())
  const [focusedIndex, setFocusedIndex] = useState<number>(-1)

  const updateConfig = useCallback((newConfig: Partial<VirtualListProps<T>>) => {
    setConfig(prev => ({ ...prev, ...newConfig }))
  }, [])

  const selectItem = useCallback((index: number) => {
    setSelectedItems(prev => new Set([...prev, index]))
  }, [])

  const deselectItem = useCallback((index: number) => {
    setSelectedItems(prev => {
      const newSet = new Set(prev)
      newSet.delete(index)
      return newSet
    })
  }, [])

  const toggleItem = useCallback((index: number) => {
    setSelectedItems(prev => {
      const newSet = new Set(prev)
      if (newSet.has(index)) {
        newSet.delete(index)
      } else {
        newSet.add(index)
      }
      return newSet
    })
  }, [])

  const selectRange = useCallback((startIndex: number, endIndex: number) => {
    setSelectedItems(prev => {
      const newSet = new Set(prev)
      const start = Math.min(startIndex, endIndex)
      const end = Math.max(startIndex, endIndex)
      
      for (let i = start; i <= end; i++) {
        newSet.add(i)
      }
      return newSet
    })
  }, [])

  const selectAll = useCallback(() => {
    setSelectedItems(new Set(Array.from({ length: items.length }, (_, i) => i)))
  }, [items.length])

  const clearSelection = useCallback(() => {
    setSelectedItems(new Set())
  }, [])

  const isSelected = useCallback((index: number) => {
    return selectedItems.has(index)
  }, [selectedItems])

  const getSelectedItems = useCallback(() => {
    return Array.from(selectedItems).map(index => items[index]).filter(Boolean)
  }, [selectedItems, items])

  const getSelectedCount = useCallback(() => {
    return selectedItems.size
  }, [selectedItems])

  return {
    config,
    updateConfig,
    selectedItems,
    focusedIndex,
    setFocusedIndex,
    selectItem,
    deselectItem,
    toggleItem,
    selectRange,
    selectAll,
    clearSelection,
    isSelected,
    getSelectedItems,
    getSelectedCount
  }
}

// Enhanced Virtual List with selection support
export interface SelectableVirtualListProps<T = any> extends VirtualListProps<T> {
  selectable?: boolean
  multiSelect?: boolean
  selectedItems?: Set<number>
  onSelectionChange?: (selectedItems: Set<number>) => void
  focusedIndex?: number
  onFocusChange?: (focusedIndex: number) => void
  selectAllEnabled?: boolean
  onSelectAll?: () => void
  onDeselectAll?: () => void
  getItemId?: (item: T, index: number) => string | number
}

export function SelectableVirtualList<T = any>({
  selectable = false,
  multiSelect = false,
  selectedItems = new Set(),
  onSelectionChange,
  focusedIndex = -1,
  onFocusChange,
  selectAllEnabled = false,
  onSelectAll,
  onDeselectAll,
  getItemId,
  renderItem: originalRenderItem,
  ...props
}: SelectableVirtualListProps<T>) {
  const [lastSelectedIndex, setLastSelectedIndex] = useState<number>(-1)

  const handleItemClick = useCallback((index: number, event?: React.MouseEvent) => {
    if (!selectable || !onSelectionChange) return

    const newSelection = new Set(selectedItems)

    if (multiSelect && event?.shiftKey && lastSelectedIndex !== -1) {
      // Shift+click için range selection
      const start = Math.min(lastSelectedIndex, index)
      const end = Math.max(lastSelectedIndex, index)
      
      for (let i = start; i <= end; i++) {
        newSelection.add(i)
      }
    } else if (multiSelect && (event?.ctrlKey || event?.metaKey)) {
      // Ctrl/Cmd+click için toggle
      if (newSelection.has(index)) {
        newSelection.delete(index)
      } else {
        newSelection.add(index)
      }
    } else if (multiSelect) {
      // Normal click in multi-select mode
      if (newSelection.has(index)) {
        newSelection.delete(index)
      } else {
        newSelection.add(index)
      }
    } else {
      // Single select mode
      newSelection.clear()
      newSelection.add(index)
    }

    setLastSelectedIndex(index)
    onSelectionChange(newSelection)
    onFocusChange?.(index)
  }, [selectable, multiSelect, selectedItems, onSelectionChange, lastSelectedIndex, onFocusChange])

  const handleKeyDown = useCallback((event: React.KeyboardEvent) => {
    if (!selectable) return

    switch (event.key) {
      case 'Enter':
      case ' ':
        event.preventDefault()
        if (focusedIndex >= 0 && focusedIndex < props.items.length) {
          handleItemClick(focusedIndex)
        }
        break
      case 'a':
        if ((event.ctrlKey || event.metaKey) && multiSelect && selectAllEnabled) {
          event.preventDefault()
          if (onSelectAll) {
            onSelectAll()
          }
        }
        break
      case 'Escape':
        if (multiSelect && onDeselectAll) {
          event.preventDefault()
          onDeselectAll()
        }
        break
    }
  }, [selectable, focusedIndex, props.items.length, handleItemClick, multiSelect, selectAllEnabled, onSelectAll, onDeselectAll])

  const renderItem = useCallback((item: T, index: number) => {
    const isSelected = selectedItems.has(index)
    const isFocused = focusedIndex === index
    const itemId = getItemId ? getItemId(item, index) : index
    
    return (
      <div
        key={itemId}
        className={cn(
          "transition-colors outline-none",
          selectable && "cursor-pointer hover:bg-muted/50",
          isSelected && "bg-primary/10 border-l-4 border-primary",
          isFocused && "ring-2 ring-ring ring-offset-2"
        )}
        onClick={(e) => selectable && handleItemClick(index, e)}
        onKeyDown={handleKeyDown}
        tabIndex={selectable ? 0 : undefined}
        role={selectable ? "option" : undefined}
        aria-selected={selectable ? isSelected : undefined}
        aria-label={selectable ? `Item ${index + 1}${isSelected ? ', selected' : ''}` : undefined}
      >
        {originalRenderItem(item, index)}
      </div>
    )
  }, [originalRenderItem, selectable, selectedItems, focusedIndex, handleItemClick, handleKeyDown, getItemId])

  return <VirtualList {...props} renderItem={renderItem} />
}

// Export types