// Import libs
import clone from 'fast-clone';

// Import shared constants
import presetColors from '../constants/presetColors';

// Import shared helpers
import colorsAreSame from './colorsAreSame';

// Import shared types
import Color from '../types/Color';

// List of all colors in the order they will be distributed
const allColors = [
  presetColors.red,
  presetColors.blue,
  presetColors.yellow,
  presetColors.green,
  presetColors.orange,
  presetColors.purple,
];

/**
 * Add colors to elements that don't have colors
 * @author Gabe Abrams
 * @param items list of items that may or may not have a color prop
 * @returns items with a color prop defined on every item
 */
const addColors = (items: any[]): any[] => {
  // If one or zero items, this is simple: just give it a color
  if (items.length === 0) {
    return [];
  }
  if (items.length === 1) {
    return [{
      ...items,
      color: (items[0].color ?? allColors[0]),
    }];
  }

  // first clone items
  const itemsClone = clone(items);

  // Index of the next color
  let nextColorIndex = 0;

  itemsClone.forEach((item: any, index: number) => {
    // If user includes a color, just keep it
    if (item.color) {
      return item;
    }

    // Get the previous color (if there is one), otherwise leave it undefined
    const prevItemIndex = (
      index === 0
        ? itemsClone.length - 1 // last item
        : index - 1 // prev item
    );
    const prevItemColor = itemsClone[prevItemIndex].color;

    // Get the next color (if there is one), otherwise leave it undefined
    const nextItemIndex = (
      index === itemsClone.length - 1
        ? 0 // first item
        : index + 1 // next item
    );
    const nextItemColor = itemsClone[nextItemIndex].color;

    // Keep choosing colors until different from neighbors
    let color: Color = allColors[nextColorIndex];
    for (let i = 0; i < 3; i++) {
      // Get the next candidate color
      const candidateColor = allColors[nextColorIndex + i];

      // Check if this candidate color matches the prev/next color
      const candidateColorIsSame = (
        colorsAreSame(candidateColor, prevItemColor)
        || colorsAreSame(candidateColor, nextItemColor)
      );

      // If this is a unique color, keep it!
      if (!candidateColorIsSame) {
        // Save the color
        color = candidateColor;

        // Increment next color index
        nextColorIndex += ((i + 1) % allColors.length);
        break;
      }
    }

    // Save the color to the item
    itemsClone[index].color = color;
  });

  // return the cloned list
  return itemsClone;
};

export default addColors;
