export enum SortByOptions {
  state = "state",
  label = "label",
  calculatedScore = "calculatedScore",
  defaultScore = "defaultScore",
}

export enum SortByOrderOptions {
  ascending = "ascending",
  descending = "descending",
}

export const sortByCalculatedScore = (a: any, b: any): number => {
  if (a.calculatedScore > b.calculatedScore) {
    return -1;
  }
  if (a.calculatedScore < b.calculatedScore) {
    return 1;
  }
  return 0;
};

export const normalizeString = (str: any): string => {
  if (str !== null && str !== undefined && isString(str)) {
    return str
      .normalize("NFD")
      .replace(/[\u0300-\u036f]/g, "") // remove accents
      .toLocaleLowerCase();
  }
  return "";
};

export const hasTerm = (term: string, str: string): boolean => {
  if (normalizeString(str).includes(normalizeString(term))) {
    return true;
  }
  return false;
};

export const sortByDateField = (a: any, b: any, order: any) => {
  const dateA = new Date(a).getTime();
  const dateB = new Date(b).getTime();

  if (dateA > dateB) {
    return order === SortByOrderOptions.ascending ? -1 : 1;
  }
  if (dateB > dateA) {
    return order === SortByOrderOptions.ascending ? 1 : -1;
  }
  return 0;
};

export const sortByStringField = (
  a: any,
  b: any,
  order: SortByOrderOptions
): number => {
  if (order === SortByOrderOptions.ascending) {
    return a.localeCompare(b);
  } else if (order === SortByOrderOptions.descending) {
    return -a.localeCompare(b);
  }
  return 0;
};

export const sortByNumberField = (
  a: any,
  b: any,
  order: SortByOrderOptions
) => {
  if (a < b) {
    return order === SortByOrderOptions.ascending ? -1 : 1;
  } else if (a > b) {
    return order === SortByOrderOptions.ascending ? 1 : -1;
  }
  return 0;
};

export const sortByField = (
  a: any,
  b: any,
  field: any,
  order: SortByOrderOptions,
  date?: boolean,
  forceNumber?: boolean
) => {
  const itemA = a[field];
  const itemB = b[field];

  if (
    (itemA === undefined || itemA === null) &&
    (itemB !== null || itemB !== undefined)
  ) {
    return 1;
  }
  if (
    (itemB === undefined || itemB === null) &&
    (itemA !== null || itemA !== undefined)
  ) {
    return -1;
  }

  if (date === true) {
    return sortByDateField(itemA, itemB, order);
  }

  const sortStringValues = isString(itemA) && isString(itemB);
  const sortNumberValues = isNumber(itemA) && isNumber(itemB);
  // Account for null or undefined values
  if (!sortStringValues && !sortNumberValues) {
    if (
      !isNaN(itemA) &&
      isNaN(itemB) &&
      order === SortByOrderOptions.ascending
    ) {
      return -1;
    }
    if (
      !isNaN(itemA) &&
      isNaN(itemB) &&
      order === SortByOrderOptions.descending
    ) {
      return -1;
    }

    if (
      !isNaN(itemB) &&
      isNaN(itemA) &&
      order === SortByOrderOptions.ascending
    ) {
      return 1;
    }
    if (
      !isNaN(itemB) &&
      isNaN(itemA) &&
      order === SortByOrderOptions.descending
    ) {
      return 1;
    }
    if (isNaN(itemA) && isNaN(itemB)) {
      return 0;
    }

    if (itemA === null && itemB === null) {
      return 0;
    } else if (itemA === null && itemB !== null) {
      return 1;
    } else if (itemB !== null && itemB === null) {
      return -1;
    }
  }

  if (sortStringValues) {
    if (forceNumber) {
      return sortByNumberField(parseFloat(itemA), parseFloat(itemB), order);
    }
  }

  if (sortStringValues) {
    return sortByStringField(itemA, itemB, order);
  } else if (sortNumberValues) {
    return sortByNumberField(itemA, itemB, order);
  }

  return 0;
};

export const sortByValue = (
  itemA: any,
  itemB: any,
  order: SortByOrderOptions,
  date?: boolean
) => {
  if (
    (itemA === undefined || itemA === null) &&
    (itemB !== null || itemB !== undefined)
  ) {
    return 1;
  }
  if (
    (itemB === undefined || itemB === null) &&
    (itemA !== null || itemA !== undefined)
  ) {
    return -1;
  }

  const sortStringValues = isString(itemA) && isString(itemB);
  const sortNumberValues = isNumber(itemA) && isNumber(itemB);
  // Account for null or undefined values
  if (!sortStringValues && !sortNumberValues) {
    if (
      !isNaN(itemA) &&
      isNaN(itemB) &&
      order === SortByOrderOptions.ascending
    ) {
      return -1;
    }
    if (
      !isNaN(itemA) &&
      isNaN(itemB) &&
      order === SortByOrderOptions.descending
    ) {
      return -1;
    }

    if (
      !isNaN(itemB) &&
      isNaN(itemA) &&
      order === SortByOrderOptions.ascending
    ) {
      return 1;
    }
    if (
      !isNaN(itemB) &&
      isNaN(itemA) &&
      order === SortByOrderOptions.descending
    ) {
      return 1;
    }
    if (isNaN(itemA) && isNaN(itemB)) {
      return 0;
    }

    if (itemA === null && itemB === null) {
      return 0;
    } else if (itemA === null && itemB !== null) {
      return 1;
    } else if (itemB !== null && itemB === null) {
      return -1;
    }
  }

  if (date === true) {
    return sortByDateField(itemA, itemB, order);
  }
  if (sortStringValues) {
    return sortByStringField(itemA, itemB, order);
  } else if (sortNumberValues) {
    return sortByNumberField(itemA, itemB, order);
  }

  return 0;
};

export const isString = (value: any) => {
  return typeof value === "string" || value instanceof String;
};

export const isNumber = (value: any) => {
  return (typeof value === "number" || isFinite(value)) && !isNaN(value);
};
