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

import { xyCheck } from './xyCheck.ts';

export interface XYJoinXOptions {
  /**
   * The range in which the two x values of the 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;
}

/**
 * Join x / y values when difference in X is closer than delta.
 * When joining, y values are summed and x values are weighted average
 * @param data - object that contains property x (an ordered increasing array) and y (an array).
 * @param options - options.
 * @returns an object with joined x and summed y values.
 */
export function xyJoinX(
  data: DataXY,
  options: XYJoinXOptions = {},
): DataXY<number[]> {
  xyCheck(data);
  const { delta = 1 } = options;
  const deltaIsFunction = typeof delta === 'function';
  const x = Array.from(data.x);
  const y = Array.from(data.y);
  if (x.length < 2) {
    return { x, y };
  }
  let position = 0;

  for (let i = 1; i < x.length; i++) {
    const difference = x[i] - x[i - 1];
    const currentDelta = deltaIsFunction ? delta((x[i] + x[i - 1]) / 2) : delta;

    if (difference <= currentDelta) {
      // we join
      if (y[position] !== 0 || y[i] !== 0) {
        x[position] =
          (x[position] * y[position] + x[i] * y[i]) / (y[position] + y[i]);
        y[position] += y[i];
      }
    } else {
      position++;
      x[position] = x[i];
      y[position] = y[i];
    }
  }

  x.length = position + 1;
  y.length = position + 1;
  return { x, y };
}
