import type { ID } from '../../../types';
import { partition } from '../util';
import { ConflictEntry } from './resolve-conflicts';

export const sort = (
  entries: ConflictEntry[],
  biasRight?: boolean,
  usePrev?: boolean,
  keepNodeOrder?: boolean,
) => {
  const parts = partition(entries, (entry) => {
    const hasFixOrder =
      entry.hasOwnProperty('fixorder') && !isNaN(entry.fixorder!);
    if (keepNodeOrder) {
      return !hasFixOrder && entry.hasOwnProperty('barycenter');
    }
    // NOTE: 有fixorder的也可以排
    return hasFixOrder || entry.hasOwnProperty('barycenter');
  });
  const sortable = parts.lhs;
  const unsortable = parts.rhs.sort((a, b) => -a.i - -b.i);
  const vs: ID[][] = [];
  let sum = 0;
  let weight = 0;
  let vsIndex = 0;

  sortable?.sort(compareWithBias(!!biasRight, !!usePrev));

  vsIndex = consumeUnsortable(vs, unsortable, vsIndex);

  sortable?.forEach((entry) => {
    vsIndex += entry.vs?.length;
    vs.push(entry.vs);
    sum += entry.barycenter! * entry.weight!;
    weight += entry.weight!;
    vsIndex = consumeUnsortable(vs, unsortable, vsIndex);
  });

  const result: { vs: ID[]; barycenter?: number; weight?: number } = {
    vs: vs.flat(),
  };
  if (weight) {
    result.barycenter = sum / weight;
    result.weight = weight;
  }
  return result;
};

const consumeUnsortable = (
  vs: ID[][],
  unsortable: ConflictEntry[],
  index: number,
) => {
  let iindex = index;
  let last;
  while (
    unsortable.length &&
    (last = unsortable[unsortable.length - 1]).i <= iindex
  ) {
    unsortable.pop();
    vs?.push(last.vs);
    iindex++;
  }
  return iindex;
};

/**
 * 配置是否考虑使用之前的布局结果
 */
const compareWithBias = (bias: boolean, usePrev: boolean) => {
  return (entryV: ConflictEntry, entryW: ConflictEntry) => {
    // 排序的时候先判断fixorder，不行再判断重心
    if (entryV.fixorder !== undefined && entryW.fixorder !== undefined) {
      return entryV.fixorder - entryW.fixorder;
    }
    if (entryV.barycenter! < entryW.barycenter!) {
      return -1;
    }
    if (entryV.barycenter! > entryW.barycenter!) {
      return 1;
    }
    // 重心相同，考虑之前排好的顺序
    if (usePrev && entryV.order !== undefined && entryW.order !== undefined) {
      if (entryV.order < entryW.order) {
        return -1;
      }
      if (entryV.order > entryW.order) {
        return 1;
      }
    }

    return !bias ? entryV.i - entryW.i : entryW.i - entryV.i;
  };
};
