import React, { useReducer } from 'react';
import { useAnimatedListItems } from './useAnimatedListItems';

type Mutation = 'reverse' | 'randomize' | 'insert' | 'remove';

/**
 * Randomizer function shamelessly copied unmodified from https://stackoverflow.com/a/12646864
 *
 * License: https://creativecommons.org/licenses/by-sa/4.0/
 *
 * Author(s):
 * - https://stackoverflow.com/users/310500/laurens-holst
 * - https://stackoverflow.com/users/8112776/ashleedawg
 */
function shuffleArray(array) {
  for (let i = array.length - 1; i > 0; i--) {
    const j = Math.floor(Math.random() * (i + 1));
    [array[i], array[j]] = [array[j], array[i]];
  }
}

function insertRandomlyIntoArray(array: string[]): string[] {
  const insertBefore = Math.floor(Math.random() * (array.length + 1));
  const newItem = `Serial Number ${crypto.randomUUID()}`;
  if (insertBefore === 0) {
    return [newItem, ...array];
  }
  return [
    ...array.slice(0, insertBefore),
    newItem,
    ...array.slice(insertBefore),
  ];
}

function removeRandomlyFromArray(array: string[]): string[] {
  const removeIndex = Math.floor(Math.random() * array.length);
  if (removeIndex === 0) {
    return [...array.slice(1)];
  }
  if (removeIndex === array.length) {
    return [...array.slice(0, -1)];
  }
  return [...array.slice(0, removeIndex), ...array.slice(removeIndex + 1)];
}

export const AnimatedListDemo = () => {
  const [items, mutateItems] = useReducer(
    (prevState: string[], mutation: Mutation) => {
      let newState: string[] = [...prevState];
      switch (mutation) {
        case 'reverse':
          newState.reverse();
          break;
        case 'randomize':
          shuffleArray(newState);
          break;
        case 'insert':
          newState = insertRandomlyIntoArray(newState);
          break;
        case 'remove':
          newState = removeRandomlyFromArray(newState);
          break;
        default:
          return prevState;
      }
      return newState;
    },
    [
      `Serial Number ${crypto.randomUUID()}`,
      `Serial Number ${crypto.randomUUID()}`,
      `Serial Number ${crypto.randomUUID()}`,
      `Serial Number ${crypto.randomUUID()}`,
    ],
  );

  const { updateItemRef, updateItemPositions, itemStyles } =
    useAnimatedListItems({ keys: items });

  return (
    <main>
      <button
        type="button"
        onClick={() => {
          updateItemPositions();
          mutateItems('reverse');
        }}
      >
        Reverse
      </button>
      <button
        type="button"
        onClick={() => {
          updateItemPositions();
          mutateItems('randomize');
        }}
      >
        Randomize
      </button>
      <button
        type="button"
        onClick={() => {
          updateItemPositions();
          mutateItems('insert');
        }}
      >
        Insert
      </button>
      <button
        type="button"
        onClick={() => {
          updateItemPositions();
          mutateItems('remove');
        }}
      >
        Remove
      </button>

      <ol>
        {items.map((item) => {
          return (
            <li
              key={item}
              ref={(li) => updateItemRef(item, li)}
              style={itemStyles[item]}
            >
              {item}
            </li>
          );
        })}
      </ol>
    </main>
  );
};
