import type { DataXY, NumberArray } from 'cheminfo-types';

import { getSlotsToFirst } from './utils/getSlotsToFirst.ts';

export interface XYArrayAlignToFirstOptions {
  /**
   * The range in which the two x values of the data/spectra must be to be placed on the same line. It may also be a function that allows to change `delta` depending on the X values of the spectrum
   * @default 1
   */
  delta?: ((arg: number) => number) | number;
}

/**
 * We align all the data/spectra to the first array of X.
 * The alignment is based on the X values of the first spectrum and the `delta` error allowed.
 * If some x values are missing in the first spectrum we will add them
 * @param data - data
 * @param options - options
 */
export function xyArrayAlignToFirst(
  data: DataXY[],
  options: XYArrayAlignToFirstOptions = {},
): {
  x: NumberArray;
  ys: NumberArray[];
} {
  const { delta = 1 } = options;
  const slots = getSlotsToFirst(data, { delta });
  const x = Float64Array.from(slots.map((slot) => slot.value));
  const ys = Array.from(data, () => new Float64Array(x.length));

  const positions = new Uint32Array(data.length);
  for (let i = 0; i < slots.length; i++) {
    const slot = slots[i];
    for (let j = 0; j < data.length; j++) {
      const spectrum = data[j];
      while (
        positions[j] < spectrum.x.length &&
        spectrum.x[positions[j]] < slot.to
      ) {
        ys[j][i] += spectrum.y[positions[j]];
        positions[j]++;
      }
    }
  }

  return { x, ys };
}
