import { randomBytes } from "crypto";
import type { UUID } from "./types";

const UUID_TICKS_PER_MS = 10000;
const GREGORIAN_OFFSET = BigInt(0x01b21dd213814000);
const clockSequence = Math.floor(Math.random() * 0x3fff);
const nodeId = randomBytes(6);

export function v1(): UUID {
  const now = BigInt(Date.now()) * BigInt(UUID_TICKS_PER_MS) + GREGORIAN_OFFSET;

  const timeLow = Number(now & 0xffffffffn);
  const timeMid = Number((now >> 32n) & 0xffffn);
  const timeHighAndVersion = Number((now >> 48n) & 0x0fffn) | 0x1000;

  const clockSeqAndReserved = (clockSequence & 0x3fff) | 0x8000;

  const uuid = [
    timeLow.toString(16).padStart(8, "0"),
    timeMid.toString(16).padStart(4, "0"),
    timeHighAndVersion.toString(16).padStart(4, "0"),
    clockSeqAndReserved.toString(16).padStart(4, "0"),
    nodeId.toString("hex"),
  ].join("-");

  return uuid as UUID;
}
