import crypto from 'node:crypto'

/** Letras y dígitos: el alfabeto por defecto del `get_random_string` de Django. */
export const ALPHANUMERIC = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789'
/** Solo letras, para el token de seguridad (formato `uRlPBR`). */
export const LETTERS = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz'

/**
 * Código aleatorio de `length` caracteres tomados de `alphabet`.
 *
 * Estos códigos se portaron del Django original como `randomBytes(n).toString('hex')`,
 * que cambiaba el formato sin querer: hex solo usa `0-9a-f`, mientras que el
 * `get_random_string` original daba alfanumérico con mayúsculas y minúsculas.
 *
 * Muestreo por rechazo: 256 no suele ser múltiplo del tamaño del alfabeto, así que
 * `byte % alphabet.length` haría más probables sus primeros caracteres. Descartando
 * los bytes desde el múltiplo más alto que cabe en uno, el reparto queda uniforme.
 */
export function randomToken(length: number, alphabet: string = ALPHANUMERIC): string {
  const limit = 256 - (256 % alphabet.length)
  let token = ''
  while (token.length < length) {
    for (const byte of crypto.randomBytes(length)) {
      if (byte >= limit) continue
      token += alphabet[byte % alphabet.length]
      if (token.length === length) break
    }
  }
  return token
}
