/**
 * TEAM: frontend_infra
 * @flow strict
 */

import * as React from "react";
import LoadingPlaceholder from "./LoadingPlaceholder";

export type Props<T> = {|
  /** The list of items that will be tiles in this list **/
  +tiles: $ReadOnlyArray<T>,
  /** The callback called with new tile order upon drag stop **/
  +onReorder: ($ReadOnlyArray<T>) => void,
  /** The function to render the tiles **/
  +renderTile: (value: T, index: number) => React.MixedElement,
  /** A function to get a unique id from a tile **/
  +getUniqueTileId: T => string,
|};

function defaultGetUniqueTileId<T>(value: T): string {
  try {
    return JSON.stringify(value) ?? "";
  } catch (error) {
    throw new Error(
      "DraggableList tile values not stringifyable. Please specify `getUniqueTileId`."
    );
  }
}

type DraggableProps<T> = {|
  /** The list of items that will be tiles in this list **/
  +tiles: $ReadOnlyArray<T>,
  /** The callback called with new tile order upon drag stop **/
  +onReorder: ($ReadOnlyArray<T>) => void,
  /** The function to render the tiles **/
  +renderTile: (value: T, index: number) => React.MixedElement,
  /** A function to get a unique id from a tile **/
  +getUniqueTileId?: T => string,
|};

/**
 * @short A list with rearrangeable items
 * @brandStatus V3
 * @status Stable
 * @category Layout
 *
 * DraggableList creates a list of items that the user can rearrange by drag and dropping items.
 */
function DraggableList<T>({
  getUniqueTileId = defaultGetUniqueTileId,
  ...rest
}: DraggableProps<T>): React.Node {
  const RawDraggableList = React.useMemo(
    () =>
      React.lazy<Props<T>>(
        () =>
          import(
            /* webpackChunkName: "latitude_DraggableList_RawDraggableList" */ "./RawDraggableList"
          )
      ),
    []
  );
  const props = {getUniqueTileId, ...rest};
  return (
    <React.Suspense fallback={<LoadingPlaceholder {...props} />}>
      <RawDraggableList {...props} />
    </React.Suspense>
  );
}

export default DraggableList;
