stMap[msecs];
    if (list !== undefined && L.isEmpty(list)) {
      debug('unenroll: list empty');
      timerListQueue.removeAt(list.priorityQueuePosition);
      delete timerListMap[list.msecs];
    }

    decRefCount();
  }

  // If active is called later, then we want to make sure not to insert again
  item._idleTimeout = -1;
}

// Make a regular object able to act as a timer by setting some properties.
// This function does not start the timer, see `active()`.
// Using existing objects as timers slightly reduces object overhead.
function enroll(item, msecs) {
  msecs = getTimerDuration(msecs, 'msecs');

  // If this item was already in a list somewhere
  // then we should unenroll it from that
  if (item._idleNext) unenroll(item);

  L.init(item);
  item._idleTimeout = msecs;
}


/**
 * Schedules the execution of a one-time `callback`
 * after `after` milliseconds.
 * @param {Function} callback
 * @param {number} [after]
 * @param {any} [arg1]
 * @param {any} [arg2]
 * @param {any} [arg3]
 * @returns {Timeout}
 */
function setTimeout(callback, after, arg1, arg2, arg3) {
  validateFunction(callback, 'callback');

  let i, args;
  switch (arguments.length) {
    // fast cases
    case 1:
    case 2:
      break;
    case 3:
      args = [arg1];
      break;
    case 4:
      args = [arg1, arg2];
      break;
    default:
      args = [arg1, arg2, arg3];
      for (i = 5; i < arguments.length; i++) {
        // Extend array dynamically, makes .apply run much faster in v6.0.0
        args[i - 2] = arguments[i];
      }
      break;
  }

  const timeout = new Timeout(callback, after, args, false, true);
  insert(timeout, timeout._idleTimeout);

  return timeout;
}

ObjectDefineProperty(setTimeout, customPromisify, {
  __proto__: null,
  enumerable: true,
  get() {
    if (!timersPromises)
      timersPromises = require('timers/promises');
    return timersPromises.setTimeout;
  },
});

/**
 * Cancels a timeout.
 * @param {Timeout | string | number} timer
 * @returns {void}
 */
function clearTimeout(timer) {
  if (timer && timer._onTimeout) {
    timer._onTimeout = null;
    unenroll(timer);
    return;
  }
  if (typeof timer === 'number' || typeof timer === 'string') {
    const timerInstance = knownTimersById[timer];
    if (timerInstance !== undefined) {
      timerInstance._onTimeout = null;
      unenroll(timerInstance);
    }
  }
}

/**
 * Schedules repeated execution of `callback`
 * every `repeat` milliseconds.
 * @param {Function} callback
 * @param {number} [repeat]
 * @param {any} [arg1]
 * @param {any} [arg2]
 * @param {any} [arg3]
 * @returns {Timeout}
 */
function setInterval(callback, repeat, arg1, arg2, arg3) {
  validateFunction(callback, 'callback');

  let i, args;
  switch (arguments.length) {
    // fast cases
    case 1:
    case 2:
      break;
    case 3:
      args = [arg1];
      break;
    case 4:
      args = [arg1, arg2];
      break;
    default:
      args = [arg1, arg2, arg3];
      for (i = 5; i < arguments.length; i++) {
        // Extend array dynamically, makes .apply run much faster in v6.0.0
        args[i - 2] = arguments[i];
      }
      break;
  }

  const timeout = new Timeout(callback, repeat, args, true, true);
  insert(timeout, timeout._idleTimeout);

  return timeout;
}

/**
 * Cancels an interval.
 * @param {Timeout | string | number} timer
 * @returns {void}
 */
function clearInterval(timer) {
  // clearTimeout and clearInterval can be used to clear timers created from
  // both setTimeout and setInterval, as specified by HTML Living Standard:
  // https://html.spec.whatwg.org/multipage/timers-and-user-prompts.html#dom-setinterval
  clearTimeout(timer);
}

Timeout.prototype.close = function() {
  clearTimeout(this);
  return this;
};

Timeout.prototype[SymbolDispose] = function() {
  clearTimeout(this);
};

/**
 * Coerces a `Timeout` to a primitive.
 * @returns {number}
 */
Timeout.prototype[SymbolToPrimitive] = function() {
  const id = this[async_id_symbol];
  if (!this[kHasPrimitive]) {
    this[kHasPrimitive] = true;
    knownTimersById[id] = this;
  }
  return id;
};

/**
 * Schedules the immediate execution of `callback`
 * after I/O events' callbacks.
 * @param {Function} callback
 * @param {any} [arg1]
 * @param {any} [arg2]
 * @param {any} [arg3]
 * @returns {Immediate}
 */
function setImmediate(callback, arg1, arg2, arg3) {
  validateFunction(callback, 'callback');

  let i, args;
  switch (arguments.length) {
    // fast cases
    case 1:
      break;
    case 2:
      args = [arg1];
      break;
    case 3:
      args = [arg1, arg2];
      break;
    default:
      args = [arg1, arg2, arg3];
      for (i = 4; i < arguments.length; i++) {
        // Extend array dynamically, makes .apply run much faster in v6.0.0
        args[i - 1] = arguments[i];
      }
      break;
  }

  return new Immediate(callback, args);
}

ObjectDefineProperty(setImmediate, customPromisify, {
  __proto__: null,
  enumerable: true,
  get() {
    if (!timersPromises)
      timersPromises = require('timers/promises');
    return timersPromises.setImmediate;
  },
});

/**
 * Cancels an immediate.
 * @param {Immediate} immediate
 * @returns {void}
 */
function clearImmediate(immediate) {
  if (!immediate || immediate._destroyed)
    return;

  immediateInfo[kCount]--;
  immediate._destroyed = true;

  if (immediate[kRefed] && --immediateInfo[kRefCount] === 0)
    toggleImmediateRef(false);
  immediate[kRefed] = null;

  if (destroyHooksExist() && immediate[async_id_symbol] !== undefined) {
    emitDestroy(immediate[async_id_symbol]);
  }

  immediate._onImmediate = null;

  immediateQueue.remove(immediate);
}

Immediate.prototype[SymbolDispose] = function() {
  clearImmediate(this);
};

module.exports = {
  setTimeout,
  clearTimeout,
  setImmediate,
  clearImmediate,
  setInterval,
  clearInterval,
  _unrefActive: deprecate(
    unrefActive,
    'timers._unrefActive() is deprecated.' +
    ' Please use timeout.refresh() instead.',
    'DEP0127'),
  active: deprecate(
    active,
    'timers.active() is deprecated. Please use timeout.refresh() instead.',
    'DEP0126'),
  unenroll: deprecate(
    unenroll,
    'timers.unenroll() is deprecated. Please use clearTimeout instead.',
    'DEP0096'),
  enroll: deprecate(
    enroll,
    'timers.enroll() is deprecated. Please use setTimeout instead.',
    'DEP0095'),
};
