import React, {useState, useMemo, useCallback} from 'react';
import {FlatListProps, StyleSheet, useWindowDimensions} from 'react-native';
import {BottomSheetFlatList as NativeBottomSheetFlatList} from '@gorhom/bottom-sheet';
import {InputSearch} from '@components/_HuGo/Inputs/components/InputSearch';
import {isAndroid} from '@shared/utils';

import {styles} from './styles';

// Ratio empirically chosen so the minimum snap point clears the search input +
// footer height on each platform. Android needs a larger ratio because its
// logical screen height is smaller (system UI reduces the available dp).
const SNAP_RATIO = isAndroid ? 0.6 : 0.5;
// Minimum number of items that must be visible above the footer before
// scroll is enabled — prevents the user from scrolling blank minHeight space.
const SMALL_LIST_THRESHOLD = 3;

export interface BottomSheetFlatListProps<ItemT = unknown>
  extends Omit<FlatListProps<ItemT>, 'children'> {
  data: ArrayLike<ItemT> | null | undefined;
  /**
   * Show search input. Use `filterRule` to filter data locally or `onFilterText` to filter data asynchronously.
   */
  filterable?: boolean;
  /**
   * Filter callback when a search text is typed.
   * @param item - Current item
   * @param filterText - typed text in lower case.
   */
  filterRule?: (item: ItemT, filterText: string) => boolean;
  /**
   * Filter data asynchronously. When this is defined, `filterRule` has no effect.
   * @param filterText - typed text in lower case
   */
  onFilterText?: (filterText: string) => void;
  searchPlaceholder?: string;
  paddingBottom?: number;
  useBottomSheetTextInput?: boolean;
}

export function BottomSheetFlatList<T extends object>({
  data,
  filterable,
  searchPlaceholder,
  filterRule,
  contentContainerStyle,
  ListHeaderComponent,
  onFilterText,
  paddingBottom,
  useBottomSheetTextInput = true,
  scrollEnabled: propScrollEnabled = true,
  ...props
}: BottomSheetFlatListProps<T>) {
  const [filter, setFilter] = useState('');
  const {height: windowHeight} = useWindowDimensions();

  const filteredData = useMemo(() => {
    if (
      onFilterText ||
      !filterable ||
      !filter ||
      !filterRule ||
      !Array.isArray(data)
    ) {
      return data;
    }
    return data.filter(item => filterRule(item, filter.toLowerCase()));
  }, [data, filter, filterRule, filterable, onFilterText]);

  const onSearchChange = useCallback(
    (value: string) => {
      setFilter(value);
      onFilterText?.(value);
    },
    [onFilterText],
  );

  const visibleCount = Array.isArray(filteredData) ? filteredData.length : 0;
  const minHeight = filterable
    ? Math.round(windowHeight * SNAP_RATIO)
    : undefined;
  const scrollEnabled =
    propScrollEnabled && (!filterable || visibleCount >= SMALL_LIST_THRESHOLD);

  const flattenContentContainerStyle = StyleSheet.flatten([
    styles.content,
    contentContainerStyle,
    {paddingBottom, minHeight},
  ]);

  return (
    <>
      {filterable && (
        <InputSearch
          value={filter}
          onChangeText={onSearchChange}
          placeholder={searchPlaceholder}
          style={styles.search}
          useBottomSheetTextInput={useBottomSheetTextInput}
        />
      )}
      <NativeBottomSheetFlatList
        data={filteredData}
        contentContainerStyle={flattenContentContainerStyle}
        ListHeaderComponent={ListHeaderComponent}
        scrollEnabled={scrollEnabled}
        {...props}
      />
    </>
  );
}
