/**
 * Seeded PRNG utility for deterministic mock data generation.
 *
 * Uses the mulberry32 algorithm — a fast, high-quality 32-bit PRNG that
 * produces the same sequence for a given seed, ensuring consistent data
 * across page reloads and development sessions.
 */

export interface SeededRng {
  /** Raw random float in [0, 1) */
  next(): number;
  /** Random integer in [min, max] (inclusive) */
  randomInt(min: number, max: number): number;
  /** Random float in [min, max) */
  randomFloat(min: number, max: number): number;
  /** Pick a random element from an array */
  pick<T>(array: readonly T[]): T;
  /** Fisher-Yates shuffle (returns a new array) */
  shuffle<T>(array: readonly T[]): T[];
  /** Random date between start and end (inclusive) */
  randomDate(start: Date, end: Date): Date;
}

/**
 * Create a seeded PRNG using the mulberry32 algorithm.
 *
 * @param seed - Integer seed value
 * @returns A `SeededRng` object with helper methods
 */
export function createRng(seed: number): SeededRng {
  const raw = mulberry32(seed);

  const rng: SeededRng = {
    next: raw,

    randomInt(min: number, max: number): number {
      return Math.floor(raw() * (max - min + 1)) + min;
    },

    randomFloat(min: number, max: number): number {
      return raw() * (max - min) + min;
    },

    pick<T>(array: readonly T[]): T {
      return array[Math.floor(raw() * array.length)];
    },

    shuffle<T>(array: readonly T[]): T[] {
      const copy = [...array];
      for (let i = copy.length - 1; i > 0; i--) {
        const j = Math.floor(raw() * (i + 1));
        [copy[i], copy[j]] = [copy[j], copy[i]];
      }
      return copy;
    },

    randomDate(start: Date, end: Date): Date {
      const startMs = start.getTime();
      const endMs = end.getTime();
      return new Date(startMs + Math.floor(raw() * (endMs - startMs + 1)));
    },
  };

  return rng;
}

/**
 * Mulberry32 — a fast 32-bit PRNG.
 * Returns a function that produces floats in [0, 1) on each call.
 */
function mulberry32(seed: number): () => number {
  return function () {
    seed |= 0;
    seed = (seed + 0x6d2b79f5) | 0;
    let t = Math.imul(seed ^ (seed >>> 15), 1 | seed);
    t = (t + Math.imul(t ^ (t >>> 7), 61 | t)) ^ t;
    return ((t ^ (t >>> 14)) >>> 0) / 4294967296;
  };
}
