import * as React from 'react'
import { useVirtualizer, type VirtualItem } from '@tanstack/react-virtual'
import { cn } from './cva'

export interface VirtualListProps<T> {
  items: readonly T[]
  estimateSize: number | ((index: number) => number)
  renderRow: (item: T, index: number) => React.ReactNode
  overscan?: number
  getRowKey?: (item: T, index: number) => string | number
  className?: string
  empty?: React.ReactNode
}

function readDocumentDirection(): 'ltr' | 'rtl' {
  if (typeof document === 'undefined') return 'ltr'
  return document.documentElement.dir === 'rtl' ? 'rtl' : 'ltr'
}

export function VirtualList<T>({
  items,
  estimateSize,
  renderRow,
  overscan = 5,
  getRowKey,
  className,
  empty = null,
}: VirtualListProps<T>) {
  const parentRef = React.useRef<HTMLDivElement | null>(null)
  const estimateSizeFn = React.useCallback(
    (index: number) => (typeof estimateSize === 'function' ? estimateSize(index) : estimateSize),
    [estimateSize],
  )

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

  if (items.length === 0) {
    return (
      <div role="grid" aria-rowcount={0} className={className}>
        {empty}
      </div>
    )
  }

  const virtualItems = virtualizer.getVirtualItems()
  const direction = readDocumentDirection()

  return (
    <div
      ref={parentRef}
      role="grid"
      aria-rowcount={items.length}
      dir={direction}
      className={cn('overflow-auto', className)}
    >
      <div
        style={{
          height: virtualizer.getTotalSize(),
          width: '100%',
          position: 'relative',
        }}
      >
        {virtualItems.map((virtualRow: VirtualItem) => {
          const item = items[virtualRow.index]
          if (item === undefined) return null
          const key = getRowKey ? getRowKey(item, virtualRow.index) : virtualRow.index

          return (
            <div
              key={key}
              ref={virtualizer.measureElement}
              data-index={virtualRow.index}
              role="row"
              aria-rowindex={virtualRow.index + 1}
              style={{
                position: 'absolute',
                top: 0,
                insetInlineStart: 0,
                insetInlineEnd: 0,
                transform: `translateY(${virtualRow.start}px)`,
              }}
            >
              {renderRow(item, virtualRow.index)}
            </div>
          )
        })}
      </div>
    </div>
  )
}
