/**
 * Copyright (c) Meta Platforms, Inc. and affiliates.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 *
 * @flow
 * @format
 */

'use strict';

import type { ViewToken } from '../ViewabilityHelper';
import { keyExtractor as defaultKeyExtractor } from '../VirtualizeUtils';
import View from '../../../exports/View';
import VirtualizedList from '../VirtualizedList';
import * as React from 'react';
import invariant from 'fbjs/lib/invariant';
type Item = any;
export type SectionBase<SectionItemT> = {
  /**
   * The data for rendering items in this section.
   */
  data: $ReadOnlyArray<SectionItemT>,
  /**
   * Optional key to keep track of section re-ordering. If you don't plan on re-ordering sections,
   * the array index will be used by default.
   */
  key?: string,
  // Optional props will override list-wide props just for this section.
  renderItem?: ?(info: {
    item: SectionItemT,
    index: number,
    section: SectionBase<SectionItemT>,
    separators: {
      highlight: () => void,
      unhighlight: () => void,
      updateProps: (select: 'leading' | 'trailing', newProps: Object) => void,
      ...
    },
    ...
  }) => null | React.Element<any>,
  ItemSeparatorComponent?: ?React.ComponentType<any>,
  keyExtractor?: (item: SectionItemT, index?: ?number) => string,
  ...
};
type RequiredProps<SectionT: SectionBase<any>> = {|
  sections: $ReadOnlyArray<SectionT>
|};
type OptionalProps<SectionT: SectionBase<any>> = {|
  /**
   * Default renderer for every item in every section.
   */
  renderItem?: (info: {
    item: Item,
    index: number,
    section: SectionT,
    separators: {
      highlight: () => void,
      unhighlight: () => void,
      updateProps: (select: 'leading' | 'trailing', newProps: Object) => void,
      ...
    },
    ...
  }) => null | React.Element<any>,
  /**
   * Rendered at the top of each section. These stick to the top of the `ScrollView` by default on
   * iOS. See `stickySectionHeadersEnabled`.
   */
  renderSectionHeader?: ?(info: {
    section: SectionT,
    ...
  }) => null | React.Element<any>,
  /**
   * Rendered at the bottom of each section.
   */
  renderSectionFooter?: ?(info: {
    section: SectionT,
    ...
  }) => null | React.Element<any>,
  /**
   * Rendered at the top and bottom of each section (note this is different from
   * `ItemSeparatorComponent` which is only rendered between items). These are intended to separate
   * sections from the headers above and below and typically have the same highlight response as
   * `ItemSeparatorComponent`. Also receives `highlighted`, `[leading/trailing][Item/Separator]`,
   * and any custom props from `separators.updateProps`.
   */
  SectionSeparatorComponent?: ?React.ComponentType<any>,
  /**
   * Makes section headers stick to the top of the screen until the next one pushes it off. Only
   * enabled by default on iOS because that is the platform standard there.
   */
  stickySectionHeadersEnabled?: boolean,
  onEndReached?: ?({
    distanceFromEnd: number,
    ...
  }) => void,
|};
type VirtualizedListProps = React.ElementConfig<typeof VirtualizedList>;
export type Props<SectionT> = {|
  ...RequiredProps<SectionT>,
  ...OptionalProps<SectionT>,
  ...$Diff<VirtualizedListProps, {
    renderItem: $PropertyType<VirtualizedListProps, 'renderItem'>,
    data: $PropertyType<VirtualizedListProps, 'data'>,
    ...
  }>,
|};
export type ScrollToLocationParamsType = {|
  animated?: ?boolean,
  itemIndex: number,
  sectionIndex: number,
  viewOffset?: number,
  viewPosition?: number,
|};
type State = {
  childProps: VirtualizedListProps,
  ...
};

/**
 * Right now this just flattens everything into one list and uses VirtualizedList under the
 * hood. The only operation that might not scale well is concatting the data arrays of all the
 * sections when new props are received, which should be plenty fast for up to ~10,000 items.
 */
declare class VirtualizedSectionList<SectionT: SectionBase<any>> extends React.PureComponent<Props<SectionT>, State> {
  scrollToLocation(params: ScrollToLocationParamsType): any,
  getListRef(): ?React.ElementRef<typeof VirtualizedList>,
  render(): React.Node,
  _getItem(props: Props<SectionT>, sections: ?$ReadOnlyArray<Item>, index: number): ?Item,
  _keyExtractor: any,
  _subExtractor(index: number): ?{
    section: SectionT,
    // Key of the section or combined key for section + item
    key: string,
    // Relative index within the section
    index: ?number,
    // True if this is the section header
    header?: ?boolean,
    leadingItem?: ?Item,
    leadingSection?: ?SectionT,
    trailingItem?: ?Item,
    trailingSection?: ?SectionT,
    ...
  },
  _convertViewable: any,
  _onViewableItemsChanged: any,
  _renderItem: any,
  _updatePropsFor: any,
  _updateHighlightFor: any,
  _setUpdateHighlightFor: any,
  _setUpdatePropsFor: any,
  _getSeparatorComponent(index: number, info?: ?Object, listItemCount: number): ?React.ComponentType<any>,
  _updateHighlightMap: any,
  _updatePropsMap: any,
  _listRef: ?React.ElementRef<typeof VirtualizedList>,
  _captureRef: any,
}
type ItemWithSeparatorCommonProps = $ReadOnly<{|
  leadingItem: ?Item,
  leadingSection: ?Object,
  section: Object,
  trailingItem: ?Item,
  trailingSection: ?Object,
|}>;
type ItemWithSeparatorProps = $ReadOnly<{|
  ...ItemWithSeparatorCommonProps,
  LeadingSeparatorComponent: ?React.ComponentType<any>,
  SeparatorComponent: ?React.ComponentType<any>,
  cellKey: string,
  index: number,
  item: Item,
  setSelfHighlightCallback: (cellKey: string, updateFn: ?(boolean) => void) => void,
  setSelfUpdatePropsCallback: (cellKey: string, updateFn: ?(boolean) => void) => void,
  prevCellKey?: ?string,
  updateHighlightFor: (prevCellKey: string, value: boolean) => void,
  updatePropsFor: (prevCellKey: string, value: Object) => void,
  renderItem: Function,
  inverted: boolean,
|}>;
declare function ItemWithSeparator(props: ItemWithSeparatorProps): React.Node;
export default VirtualizedSectionList;