import React, {ForwardedRef, LegacyRef, ReactNode, useCallback} from 'react';
import {
  FlatListProps,
  RefreshControl,
  FlatList as FlatListRN,
  StyleProp,
  ViewStyle,
} from 'react-native';
import {useTranslation} from 'react-i18next';
import {FlatList as FlatListGH} from 'react-native-gesture-handler';
import Animated from 'react-native-reanimated';
import {Divider} from '@components/_HuGo/Divider';
import {DEFAULT_THRESHOLD} from '@shared/constants';
import {useTheme} from '@shared/theme';
import {genericForwardRef} from '@shared/utils';

import {ListSkeleton} from '../ListSkeleton';
import {ListEmpty} from '../ListEmpty';
import {ListPresentation, PaginationType} from '../../interfaces';
import {ListFooter} from '../ListFooter';
import {styles} from './styles';

const defaultKeyExtractor = (item: unknown, _: number) =>
  `${(item as {id: number})?.id}`;

const ItemSeparator = () => <Divider style={styles.divider} />;

type FlatListGHRef<T> = ForwardedRef<FlatListGH<T>> | undefined;
type FlatListRNRef<T> = ForwardedRef<FlatListRN<T>> | undefined;

export interface ListProps<TData>
  extends Pick<
    FlatListProps<TData>,
    | 'data'
    | 'keyExtractor'
    | 'renderItem'
    | 'ListEmptyComponent'
    | 'ListFooterComponent'
    | 'style'
    | 'bounces'
    | 'scrollEnabled'
    | 'ListHeaderComponent'
    | 'onEndReachedThreshold'
    | 'getItemLayout'
    | 'ItemSeparatorComponent'
    | 'showsVerticalScrollIndicator'
    | 'keyboardDismissMode'
    | 'keyboardShouldPersistTaps'
    | 'onScroll'
    | 'contentInset'
    | 'contentOffset'
    | 'progressViewOffset'
    | 'maxToRenderPerBatch'
    | 'initialNumToRender'
    | 'windowSize'
    | 'removeClippedSubviews'
  > {
  contentStyle?: StyleProp<ViewStyle>;
  listEmptyStyle?: StyleProp<ViewStyle>;
  backgroundColor?: string;
  isLoading?: boolean;
  isError?: boolean;
  isRefreshing?: boolean;
  isFetchingNextPage?: boolean;
  hasNextPage?: boolean;
  onNextPage?: () => void;
  onRefresh?: () => void;
  errorText?: string;
  emptyText?: string;
  /**
   * Show a card container for the list or a flat list. Default is `flat`. When presentation is `card` you should use the same value for `ListItem` presentation prop, with `isFirstItem` and `isLastItem` for better UI result.
   */
  presentation?: ListPresentation;
  IconEmptyList?: ReactNode;
  titleEmptyList?: string;
  descriptionEmptyList?: string;
  withDivider?: boolean;
  withRefresh?: boolean;
  /**
   * Which pagination will be use. Default is `infiniteScroll`
   */
  paginationType?: PaginationType;
  /**
   * Loader component while next page is fetching. This is valid only when `paginationType` is `infiniteScroll`. Default is a Spinner
   */
  FetchingNextPageLoader?: ReactNode;
  animated?: boolean;
}

export function ListForwaredRef<TData>(
  {
    backgroundColor,
    data,
    isLoading,
    isError,
    isFetchingNextPage,
    hasNextPage,
    isRefreshing,
    onNextPage,
    onRefresh,
    errorText,
    emptyText,
    ListEmptyComponent,
    ListFooterComponent,
    style,
    contentStyle,
    listEmptyStyle,
    renderItem,
    IconEmptyList,
    titleEmptyList,
    descriptionEmptyList,
    withRefresh = true,
    withDivider,
    bounces = true,
    scrollEnabled = true,
    onEndReachedThreshold = DEFAULT_THRESHOLD,
    paginationType = 'infiniteScroll',
    FetchingNextPageLoader,
    presentation = 'flat',
    keyExtractor = defaultKeyExtractor,
    animated,
    ...props
  }: ListProps<TData>,
  ref: FlatListGHRef<TData> | FlatListRNRef<TData>,
) {
  const {t} = useTranslation();
  const {theme} = useTheme();
  const listEmptyText = isError
    ? errorText || t('errors.api.500', {info: ''})
    : emptyText || t('general.empty');

  const onEndReached = useCallback(() => {
    if (paginationType === 'infiniteScroll') {
      onNextPage?.();
    }
  }, [paginationType, onNextPage]);

  return animated ? (
    <Animated.FlatList
      ref={ref as FlatListRNRef<TData>}
      data={data}
      keyExtractor={keyExtractor}
      renderItem={renderItem}
      ItemSeparatorComponent={withDivider ? ItemSeparator : null}
      onEndReachedThreshold={onEndReachedThreshold}
      onEndReached={onEndReached}
      bounces={bounces}
      scrollEnabled={scrollEnabled}
      contentContainerStyle={[styles.list, style]}
      refreshControl={
        withRefresh ? (
          <RefreshControl
            refreshing={!!isRefreshing}
            onRefresh={onRefresh}
            tintColor={theme.graphics.hugo[500]}
            colors={[theme.graphics.hugo[500]]}
            progressViewOffset={props.progressViewOffset}
          />
        ) : undefined
      }
      ListEmptyComponent={
        ListEmptyComponent ||
        (isLoading ? (
          <ListSkeleton presentation={presentation} />
        ) : (
          <ListEmpty
            title={titleEmptyList || listEmptyText}
            description={descriptionEmptyList}
            IconComponent={IconEmptyList}
            style={listEmptyStyle}
          />
        ))
      }
      ListFooterComponent={
        ListFooterComponent || (
          <ListFooter
            isVisible={!isLoading && hasNextPage}
            isFetchingNextPage={isFetchingNextPage}
            paginationType={paginationType}
            FetchingNextPageLoader={FetchingNextPageLoader}
            onButtonPress={onNextPage}
          />
        )
      }
      style={[{backgroundColor}, contentStyle]}
      {...props}
    />
  ) : (
    <FlatListGH
      ref={ref as LegacyRef<FlatListGH<TData>>}
      data={data}
      keyExtractor={keyExtractor}
      renderItem={renderItem}
      ItemSeparatorComponent={withDivider ? ItemSeparator : null}
      onEndReachedThreshold={onEndReachedThreshold}
      onEndReached={onEndReached}
      bounces={bounces}
      scrollEnabled={scrollEnabled}
      contentContainerStyle={[styles.list, style]}
      refreshControl={
        withRefresh ? (
          <RefreshControl
            refreshing={!!isRefreshing}
            onRefresh={onRefresh}
            tintColor={theme.graphics.hugo[500]}
            colors={[theme.graphics.hugo[500]]}
          />
        ) : undefined
      }
      ListEmptyComponent={
        ListEmptyComponent ||
        (isLoading ? (
          <ListSkeleton presentation={presentation} />
        ) : (
          <ListEmpty
            title={titleEmptyList || listEmptyText}
            description={descriptionEmptyList}
            IconComponent={IconEmptyList}
          />
        ))
      }
      ListFooterComponent={
        ListFooterComponent || (
          <ListFooter
            isVisible={!isLoading && hasNextPage}
            isFetchingNextPage={isFetchingNextPage}
            paginationType={paginationType}
            FetchingNextPageLoader={FetchingNextPageLoader}
            onButtonPress={onNextPage}
          />
        )
      }
      style={[{backgroundColor}, contentStyle]}
      {...props}
    />
  );
}

export const List = genericForwardRef(ListForwaredRef);
