/**
 * Clamp a number between a minimum and maximum.
 * @param {number} value
 * @param {number} min
 * @param {number} max
 * @returns {number}
 */
export function clamp(value, min, max) {
  return Math.min(max, Math.max(min, value));
}

/**
 * Linear interpolation between two numbers.
 * @param {number} from
 * @param {number} to
 * @param {number} t - 0..1
 * @returns {number}
 */
export function lerp(from, to, t) {
  return from + (to - from) * t;
}

/**
 * Round a number to a specific decimal precision.
 * @param {number} value
 * @param {number} decimals
 * @returns {number}
 */
export function roundTo(value, decimals) {
  const factor = 10 ** decimals;
  return Math.round(value * factor) / factor;
}

/**
 * Create a tiny event emitter.
 * @template T
 * @returns {{ on: (listener: (payload: T) => void) => () => void, emit: (payload: T) => void, clear: () => void }}
 */
export function createEmitter() {
  /** @type {Set<(payload: T) => void>} */
  const listeners = new Set();

  return {
    on(listener) {
      listeners.add(listener);
      return () => listeners.delete(listener);
    },
    emit(payload) {
      for (const listener of listeners) {
        listener(payload);
      }
    },
    clear() {
      listeners.clear();
    }
  };
}
