Source: support-lib.js

const Complex = require('./complex.js')

/**
 * Calculates the factorial of a given number.
 *
 * @param {number} num - The number to calculate the factorial of.
 * @returns {Complex} The factorial of the given number.
 * @throws {Error} If the number has a non-zero imaginary part.
 * @throws {Error} If the number is not an integer.
 * @throws {Error} If the number is negative.
 */
const factorial = function(num) {
  if (num?.im && num?.im !== 0) throw new Error(`Imaginary part must be zero. Instead is ${num.im}`);
  let n = Number(num?.re) || Number(num); 
  if (!Number.isInteger(n)) throw new Error(`Not an Integer number ${n}`);
  if ( n < 0) throw new Error(`Factorial of negative number ${n}`);
  let result = Complex(1);
  if (n === 0) return result;
  for (let i = 1; i <= n; i++) {
    result = result.mul(i);
  }
  return Complex({re: result.re, im: num.im});
};

/**
 * Returns the maximum of two complex numbers.
 *
 * @param {Object} a - The first complex number.
 * @param {number} a.re - The real part of the first complex number.
 * @param {number} a.im - The imaginary part of the first complex number.
 * @param {Object} b - The second complex number.
 * @param {number} b.re - The real part of the second complex number.
 * @param {number} b.im - The imaginary part of the second complex number.
 * @returns {Object} - The maximum complex number.
 */
const max = function(a, b) {
  if (a.re > b.re) return a;
  if (a.re < b.re) return b;
  // If we reached here is a.re === b.re
  if (a.im > b.im) return a;
  if (a.im < b.im) return b;
  return a;
}

/**
 * Returns the minimum of two complex numbers.
 *
 * @param {Complex} a - The first complex number.
 * @param {Complex} b - The second complex number.
 * @returns {Complex} The minimum of the two complex numbers.
 */
const min = function(a, b) {
  if (a.re < b.re) return a;
  if (a.re > b.re) return b;
  // If we reached here is a.re === b.re
  if (a.im < b.im) return a;
  if (a.im > b.im) return b;
  return a;
}

/**
 * Prints the given values to the console.
 * @param {...*} x - The values to be printed.
 * @returns {Array} - An array containing the printed values.
 */
const print = (...x) => { console.log(...x); return x; } 

/**
 * Writes the provided arguments to the console.
 * @param {...*} x - The values to be written to the console.
 * @returns {Array} - An array containing the string representations of the provided values.
 */
const write = (...x) => { let r = x.map(s => s.toString()); console.log(...r); return r; } 

module.exports = {
  Complex,
  print,
  write,
  factorial,
  max,
  min
};