import {
  funRound,
  TMixed,
  funSMA,
  checkArrayOfNumbers,
  checkNumber,
} from "../common";

/**
 * Computes the Relative Strength Index (RSI) for a given period.
 * @param {number[]} CLOSE - array of closing prices.
 * @param {number} N1 - number of periods for RSI1.default is 6.
 * @param {number} N2 - number of periods for RSI2.default is 12.
 * @param {number} N3 - number of periods for RSI3.default is 24.
 * @returns {{ RSI1: TMixed[]; RSI2: TMixed[]; RSI3: TMixed[] }} - object containing the RSI values for each period.
 */
export function RSI(
  CLOSE: number[],
  N1: number = 6,
  N2: number = 12,
  N3: number = 24
): { RSI1: TMixed[]; RSI2: TMixed[]; RSI3: TMixed[] } {
  // check input data
  checkArrayOfNumbers(CLOSE, "CLOSE");

  // check n and m parameters
  checkNumber(N1, 2, CLOSE, "N1", "CLOSE");
  checkNumber(N2, N1, CLOSE, "N2", "CLOSE");
  checkNumber(N3, N2, CLOSE, "N3", "CLOSE");

  // - Inner function that returns a computed function
  const innerfun = (arr: TMixed[]): ((n: number) => TMixed[]) => {
    const [up, all] = arr.slice(1).reduce(
      (acc: [TMixed[], TMixed[]], cur, i) => {
        if (cur === null || arr[i] === null) {
          acc[0].push(null);
          acc[1].push(null);
        } else {
          const diff = cur - arr[i];
          acc[0].push(Math.max(0, diff));
          acc[1].push(Math.abs(diff));
        }
        return acc;
      },
      [[], []]
    );
    return (n: number): TMixed[] => {
      const uArr = funSMA(up, n, 1);
      const aArr = funSMA(all, n, 1);
      return uArr.reduce(
        (acc: TMixed[], cur, i) => {
          if (cur === null || aArr[i] === null) {
            acc.push(null);
          } else if (aArr[i] === 0) {
            acc.push(0);
          } else {
            acc.push(funRound((cur / aArr[i]) * 100, 3));
          }
          return acc;
        },
        [null]
      );
    };
  };
  const funRsi = innerfun(CLOSE); // - Initialize the array and return the computed function
  const [RSI1, RSI2, RSI3] = [N1, N2, N3].map((n) => funRsi(n)); // - Compute the RSI values for each period
  return { RSI1, RSI2, RSI3 };
}
