import * as React from 'react';
import ReactList from 'react-list';
import once from 'lodash-es/once';

export interface ListProps {
  itemRenderer: <T>(index: number, key: string) => React.ReactElement<T>;
  getNextPage: () => void;
  length: number;
  className: string;
  initialPageSize: number;
}

const PAGE_SIZE = 20;

export class List extends React.Component<ListProps, {}> {
  private getNextPageOnce: () => void;

  constructor(props: ListProps) {
    super(props);
    this.getNextPageOnce = once(this.props.getNextPage);
  }

  componentWillReceiveProps(nextProps: ListProps): void {
    /**
     * There are some inefficiencies to the render logic in the tree above
     * this which causes this to be re-rendered more than it needs to be,
     * which breaks the once() and causes more fetches than needed.
     * This conditional fixes that as a stopgap, but can be removed
     * when render performance is fixed.
     */
    if (this.props.length !== nextProps.length) {
      this.getNextPageOnce = once(this.props.getNextPage);
    }
  }

  render(): JSX.Element {
    return (
      <ReactList
        itemRenderer={this.handleRenderRequest}
        itemsRenderer={this.itemsRenderer}
        length={this.props.length}
        type="uniform"
        pageSize={PAGE_SIZE}
        minSize={this.props.initialPageSize}
        // Do not use static size since the CSS will change the size of items
        // and the number of items in a row when the device is rotated.
        useStaticSize={false}
      />
    );
  }

  itemsRenderer = <T, U>(
    items: React.ReactElement<T>[],
    ref: React.Ref<{}>,
  ): React.ReactElement<U> => {
    return (
      <div ref={ref} className={this.props.className}>
        {items}
      </div>
    );
  };

  handleRenderRequest = <T extends {}>(
    index: number,
    key: string,
  ): React.ReactElement<T> => {
    const numberOfGames = this.props.length;
    if (numberOfGames - index <= PAGE_SIZE * 2) {
      this.getNextPageOnce();
    }
    return this.props.itemRenderer(index, key);
  };
}
