export const decalerElementsVersLaDroite = (tab: any[]) => {
  const dernierElement = tab[tab.length - 1];

  let dernierElementRecontre = tab[0];

  for (let i = 1; i < tab.length; i++) {
    let temp = tab[i];
    tab[i] = dernierElementRecontre;
    dernierElementRecontre = temp;
  }

  tab[0] = dernierElement;
};

export function shiftArrayToRight(arr: any[], places: number) {
  for (let i = 0; i < places; i++) {
    arr.unshift(arr.pop());
  }
}

export function shiftArrayToLeft(arr: any[], places: number) {
  for (let i = 0; i < places; i++) {
    arr.push(arr.shift());
  }
}

export const diviserArray = (arr: any[], nombreDeGroupe: number): any[] => {
  const result: any[] = [];

  const array = [...arr];
  const initialLength = array.length;

  let cpt = 0;

  while (array.length < nombreDeGroupe) {
    if (cpt === initialLength - 1) {
      cpt = 0;
    }

    array.push(array[cpt]);
    cpt++;
  }

  for (let i = 1; i <= nombreDeGroupe; i++) {
    result.push([]);
  }

  const wordsPerLine = Math.ceil(array.length / nombreDeGroupe);

  for (let line = 0; line < nombreDeGroupe; line++) {
    for (let i = 0; i < wordsPerLine; i++) {
      const value = array[i + line * wordsPerLine];
      if (!value) continue; //avoid adding "undefined" values
      result[line].push(value);
    }
  }

  return result;
};

export const initNullTab = (length: number) => {
  const tab = [];
  for (let i = 1; i <= length; i++) {
    tab.push(null);
  }

  return tab;
};

export const deepCloneArrayOrObject = (arr: any) =>
  JSON.parse(JSON.stringify(arr));

export const echangeDeuxElementsDePlace = (
  arr: any[],
  pos1: number,
  pos2: number
) => {
  let temp = arr[pos1];
  arr[pos1] = arr[pos2];
  arr[pos2] = temp;
};

export function splitToChunks(arr: any[], n: number) {
  const array = [...arr];
  const initialLength = array.length;

  let cpt = 0;

  while (array.length < n) {
    if (cpt === initialLength - 1) {
      cpt = 0;
    }

    array.push(array[cpt]);
    cpt++;
  }

  var rest = array.length % n, // how much to divide
    restUsed = rest, // to keep track of the division over the elements
    partLength = Math.floor(array.length / n),
    _result = [];

  for (var i = 0; i < array.length; i += partLength) {
    var end = partLength + i,
      add = false;

    if (rest !== 0 && restUsed) {
      // should add one element for the division
      end++;
      restUsed--; // we've used one division element now
      add = true;
    }

    _result.push(array.slice(i, end)); // part of the array

    if (add) {
      i++; // also increment i in the case we added an extra element for division
    }
  }

  return _result;
}

export const shuffleArray = (array: any[]) => {
  const tempArray = [...array];
  for (let i = tempArray.length - 1; i > 0; i--) {
    const j = Math.floor(Math.random() * (i + 1));
    const temp = tempArray[i];
    tempArray[i] = tempArray[j];
    tempArray[j] = temp;
  }

  return tempArray;
};

export const ajouteDansTabSiPasPresent = (arr: any[], item: any) => {
  if (!arr.includes(item)) {
    arr.push(item);
  }
};

export const sortArrayObjectByProp = (arr: any[], prop: string) =>
  arr.sort((a, b) => (a[prop] > b[prop] ? 1 : -1));

export const intersection = (array1: any, array2: any) =>
  array1.filter((value: any) => array2.includes(value));

export const randomItemFromArray = (arr: any[]) =>
  arr[Math.floor(Math.random() * arr.length)];

export const estDernierElementDuTableau = (arr: any[], index: number) =>
  arr.length - 1 === index;

export const joinStringsArray = (
  strings: string[],
  separator: string
): string[] => {
  return strings.reduce((result: any[], str: string, index: number) => {
    if (index === 0) {
      return [str];
    } else {
      return [...result, separator, str];
    }
  }, []);
};

type ValeurPropriete = string | number | Date;

export function trierTableau(
  tableau: any[],
  propriete: keyof any,
  ordre: "croissant" | "decroissant" = 'croissant',
  isDate = false
): any[] {
  const fn = ordre === "croissant" ? comparerCroissant : comparerDecroissant;

  return [...tableau].sort((a, b) => fn(a[propriete], b[propriete]));
}

type Comparateur<T> = (a: T, b: T) => number;

function comparerCroissant(a: any, b: any): number {

  if (typeof a === "string" && typeof b === "string") {
    return a.localeCompare(b);
  } else if (typeof a === "number" && typeof b === "number") {
    return a - b;
  } else if (a instanceof Date && b instanceof Date) {
    return a.getTime() - b.getTime();
  }

  throw new Error("Le type de la propriété à trier n'est pas pris en charge.");
}

function comparerDecroissant<T extends ValeurPropriete>(a: T, b: T): number {
  return comparerCroissant(b, a);
}
