//@ts-check

/**
 *
 * Creates a throttled function that only invokes the provided function at most
 * once per within a given number of milliseconds.
 *
 * @template {(...args: any) => any } F
 * @template {ReturnType<F>} R
 * @template {Parameters<F>} P
 * @param {F} func
 * @param {number} [firingRateMs] Firing rate (50ms by default)
 */
export const throttle = (func, firingRateMs = 50) => {
  /** @type {R} */
  let lastResult;

  /** @type {number} */
  let last = 0;

  /** @type {null|P} */
  let funcArguments;

  /** @type {number} */
  let timeoutID = 0;

  const call = () => {
    timeoutID = 0;
    last = +new Date();
    lastResult = func.apply(null, funcArguments);
    funcArguments = null;
  };

  /***
   * @param {P} args
   */
  const throttled = (...args) => {
    funcArguments = args;
    const delta = new Date().getTime() - last;
    if (!timeoutID)
      if (delta >= firingRateMs) {
        call();
      } else {
        timeoutID = setTimeout(call, firingRateMs - delta);
      }
    return lastResult;
  };

  return throttled;
};

export default throttle