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

import * as React from "react";
import {StyleSheet, css} from "aphrodite";
import {
  SortableHandle,
  SortableElement,
  SortableContainer,
} from "react-sortable-hoc";
import StackingContext from "../StackingContext";
import colors from "../colors";
import {
  RawDragHandle,
  RawSortableElement,
  RawSortableContainer,
} from "./RawComponents";
import type {Props} from "./index";
import {CUSTOM_MODAL_Z_INDEX} from "../modal/Constants";

const DragHandle = SortableHandle(RawDragHandle);
const SortableItem = SortableElement(RawSortableElement);
const SortableList = SortableContainer(RawSortableContainer);

/** DraggableList lazy loads RawDraggableList for improved performance */
function RawDraggableList<T>({
  tiles,
  onReorder,
  renderTile,
  getUniqueTileId,
}: Props<T>): React.Node {
  function handleSortEnd({
    oldIndex,
    newIndex,
  }: {|
    +oldIndex: number,
    +newIndex: number,
  |}) {
    const newTiles = reorderItemInArray(tiles, oldIndex, newIndex);
    onReorder(newTiles);
  }
  const {isDeprecatedZIndexEnabled} = React.useContext(StackingContext);

  return (
    <SortableList
      useDragHandle={true}
      onSortEnd={handleSortEnd}
      lockAxis="y"
      helperClass={css(
        styles.listItemDrag,
        isDeprecatedZIndexEnabled && styles.listItemDragZIndex
      )}
    >
      {tiles.map((tile, index) => (
        <SortableItem
          key={getUniqueTileId(tile)}
          index={index}
          passthroughIndex={index}
          tile={tile}
          renderTile={renderTile}
          dragHandle={<DragHandle />}
        />
      ))}
    </SortableList>
  );
}

/** returns an array with the item at oldIndex moved to newIndex */
function reorderItemInArray<T>(
  arr: $ReadOnlyArray<T>,
  oldIndex: number,
  newIndex: number
): $ReadOnlyArray<T> {
  const res = arr.slice();
  // remove moved item from res
  const movedItem = res.splice(oldIndex, 1)[0];
  // insert moved item at appropriate index
  res.splice(newIndex, 0, movedItem);
  return res;
}

const styles = StyleSheet.create({
  listItemDrag: {
    boxShadow: "0px 0px 20px rgba(57, 65, 77, 0.15)",
    pointerEvents: "auto",
    cursor: "grab",

    ":after": {
      content: '""',
      position: "absolute",
      width: "100%",
      height: "100%",
      border: `1px solid ${colors.grey60}`,
    },
  },
  listItemDragZIndex: {
    // eslint-disable-next-line flexport/no-zindex-except-specific-values
    zIndex: CUSTOM_MODAL_Z_INDEX + 10,
  },
});

export default RawDraggableList;
