import compact from "lodash/compact";
import flatMap from "lodash/flatMap";
import sortBy from "lodash/sortBy";
import uniq from "lodash/uniq";

const SUFFIXES = [
  { suffix: "K", factor: 1000 },
  { suffix: "M", factor: 1000000 },
  { suffix: "G", factor: 1000000000 },
  { suffix: "T", factor: 1000000000000 },
];

/**
 * Treats rows as table rows where keys of each row are column names. For each
 * column name, checks that all cell values there are numbers (or are empty). If
 * so, chooses the maximal suitable factor suffix for those numbers. Also, makes
 * sure that all rows have the same number of columns (adding empty cells if
 * needed).
 */
export function normalizeCellNumbers(
  rows: Array<Record<string, string>>,
): typeof rows {
  if (rows.length === 0) {
    return [];
  }

  const columns = uniq(flatMap(rows, (row) => Object.keys(row)));
  for (const column of columns) {
    const values = rows.map((row) => row[column]);
    if (!values.every((v) => v === undefined || v === "" || v.match(/^\d+$/))) {
      // For the column to be normalizable, it must only include numeric and
      // empty cells.
      continue;
    }

    // Only numbers longer than 1 digit are significant.
    const min = Math.min(
      ...compact(
        values.map((v) => (v && v.length > 1 ? parseFloat(v) : undefined)),
      ),
    );
    const found = sortBy(SUFFIXES, ({ factor }) => -factor).find(
      ({ factor }) => min >= factor * 10,
    );

    if (found) {
      for (const row of rows) {
        const v = row[column];
        if (v && v.length > 1) {
          row[column] =
            `${Math.round(parseFloat(v) / found.factor)}${found.suffix}`;
        }
      }
    }

    for (const row of rows) {
      if (!(column in row)) {
        row[column] = "";
      }
    }
  }

  return rows;
}
