import {type ReactElement} from 'react'
import {FlatList, RefreshControl} from 'react-native'
import {useSafeAreaInsets} from 'react-native-safe-area-context'

import {
  EmptyState,
  type EmptyStateAction,
} from '@/components/empty-state'
import {ErrorState} from '@/components/error-state'
import {ListEnd} from '@/components/list-end'
import {LoadingState} from '@/components/loading-state'
import {cardFrame} from '@/components/ui/card'
import {Divider} from '@/components/ui/divider'
import {atoms as a, tokens, useTheme} from '@/sprinkles'

// the virtualized analogue of <List>: a full-screen, card-framed,
// divider-interleaved list that owns its own scrolling. infinite scroll
// (onEndReached), pull-to-refresh and loading/empty/error gates live here so
// every growing list behaves the same and only mounts the rows on screen
type VirtualListProps<T extends {id: string}> = {
  items: T[]
  renderItem: (item: T) => ReactElement | null
  emptyMessage: string
  emptyAction?: EmptyStateAction
  loading?: boolean
  loadingMore?: boolean
  reachedEnd?: boolean
  onEndReached?: () => void
  onRefresh?: () => void
  error?: string | null
  onRetry?: () => void
}

const onEndReachedThreshold = 0.6

export function VirtualList<T extends {id: string}>({
  items,
  renderItem,
  emptyMessage,
  emptyAction,
  loading,
  loadingMore,
  reachedEnd,
  onEndReached,
  onRefresh,
  error,
  onRetry,
}: VirtualListProps<T>) {
  const t = useTheme()
  const insets = useSafeAreaInsets()

  // first load renders the empty-slot spinner, not the pull-down one
  const refreshing = !!loading && items.length > 0

  return (
    <FlatList<T>
      data={items}
      keyExtractor={keyOf}
      style={[a.flex_1, t.atoms.bg]}
      contentInsetAdjustmentBehavior="automatic"
      automaticallyAdjustKeyboardInsets
      keyboardShouldPersistTaps="handled"
      keyboardDismissMode="interactive"
      contentContainerStyle={[
        // outer breathing + horizontal gutter; the shared card frame sits inside
        {
          marginHorizontal: tokens.space._2xl,
          marginTop: tokens.space.lg,
          marginBottom: insets.bottom + tokens.space._2xl,
        },
        cardFrame(t),
        a.px_md,
      ]}
      renderItem={({item}) => renderItem(item)}
      ItemSeparatorComponent={Divider}
      ListEmptyComponent={
        error != null ? (
          <ErrorState message={error} onRetry={onRetry} />
        ) : loading ? (
          <LoadingState />
        ) : (
          <EmptyState message={emptyMessage} action={emptyAction} />
        )
      }
      ListFooterComponent={
        loadingMore ? (
          <LoadingState />
        ) : reachedEnd && items.length > 0 ? (
          <ListEnd />
        ) : null
      }
      onEndReached={onEndReached}
      onEndReachedThreshold={onEndReachedThreshold}
      refreshControl={
        onRefresh ? (
          <RefreshControl
            refreshing={refreshing}
            onRefresh={onRefresh}
          />
        ) : undefined
      }
    />
  )
}

const keyOf = <T extends {id: string}>(item: T) => item.id
