import { randomBytes } from "node:crypto"

/**
 * A first password, generated rather than invented by whoever is typing.
 *
 * HR hands these over on paper: the client's answer of 4 August is that the HR
 * manager gives them out by hand and re-creates one when somebody loses theirs,
 * because the factory network has no internet and there is nothing to send
 * anything with. So the constraint is not secrecy in transit, it is that a
 * person reads this off a slip and types it on a factory terminal, once.
 *
 * **Three groups of four, not six.** The command-line version made six, which is
 * twenty-nine characters. That is a lot to type correctly at a machine, and
 * this is a password somebody types once and then replaces on `/settings`, so
 * its whole life is the walk from the slip to the terminal. Twelve characters
 * from a thirty-one letter alphabet is a little under sixty bits, far past
 * anything a factory network needs and short enough to read across in one
 * glance.
 *
 * The reason written here used to be that there was no screen to change it on.
 * There is one now, and it is a stronger reason rather than a weaker one: a
 * password with a known short life may be short, where one somebody keeps for a
 * year may not.
 *
 * **No O, 0, I, l, 1.** A password read off paper and mistyped is a password HR
 * has to issue again, and those five characters are where it happens.
 *
 * Not in a service, because a screen and a script both want it and neither
 * should own it.
 */

const ALPHABET = "ABCDEFGHJKMNPQRSTUVWXYZ23456789"
const GROUPS = 3
const PER_GROUP = 4

/**
 * The largest multiple of the alphabet that fits in a byte. Bytes at or above
 * it are thrown away rather than folded with `%`: 256 is not a multiple of 31,
 * so the remainder alone would make the first eight letters turn up about three
 * percent more often than the rest. It costs a redraw on roughly one byte in
 * thirty-two and removes the question entirely.
 */
const CEILING = 256 - (256 % ALPHABET.length)

export function generateFirstPassword(): string {
  const chars: string[] = []
  while (chars.length < GROUPS * PER_GROUP) {
    for (const b of randomBytes(GROUPS * PER_GROUP)) {
      if (b >= CEILING) continue
      chars.push(ALPHABET[b % ALPHABET.length]!)
      if (chars.length === GROUPS * PER_GROUP) break
    }
  }
  return Array.from({ length: GROUPS }, (_, g) =>
    chars.slice(g * PER_GROUP, (g + 1) * PER_GROUP).join(""),
  ).join("-")
}
