const currentScores = {};
const currentBestClusterIndices = {};

const rescoreAll = (target) =>
  pokemonData.forEach(({ name, jab, rgb }) => {
    currentScores[name] = {
      jab: {
        total: applyMetrics(jab.total, target.jab),
        clusters: jab.clusters.map((c) => applyMetrics(c, target.jab)),
      },
      rgb: {
        total: applyMetrics(rgb.total, target.rgb),
        clusters: rgb.clusters.map((c) => applyMetrics(c, target.rgb)),
      },
    };
  });

const getBestClusterIndex = (
  pkmn,
  space,
  { sortMetric, scaleOption, sortOrder }
) => {
  // get the scales
  const scales = scaleOption(pkmn[space]);
  // and multiply with the intended metric, and find the index of the best value
  return currentScores[pkmn.name][space].clusters
    .map((c, i) => [c[sortMetric] * scales[i], i])
    .reduce((a, b) => (sortOrder(a[0], b[0]) > 0 ? b : a))[1];
};

const getBest = (
  number,
  space,
  clusterSettings,
  { sortMetric, scaleOption, sortOrder }
) => {
  let valueExtractor;
  if (clusterSettings) {
    valueExtractor = (pkmn) => {
      const index = getBestClusterIndex(pkmn, space, clusterSettings);
      // save the index for rendering
      currentBestClusterIndices[pkmn.name] = {
        ...(currentBestClusterIndices[pkmn.name] || {}),
        [space]: index,
      };
      // and then get the *actual* score according to the sort metric
      const clusterScore =
        scaleOption(pkmn[space])[index] *
        currentScores[pkmn.name][space].clusters[index][sortMetric];
      if (!clusterSettings.multWithTotal) {
        return clusterScore;
      }
      // and then multiply it with the total score if that's needed
      return clusterScore * currentScores[pkmn.name][space].total[sortMetric];
    };
  } else {
    // ignore scaleOption if not using clusters
    valueExtractor = (pkmn) =>
      currentScores[pkmn.name][space].total[sortMetric];
  }

  return pokemonData
    .slice()
    .sort((a, b) => sortOrder(valueExtractor(a), valueExtractor(b)))
    .slice(0, number);
};
