import crypto from "node:crypto";
import { writeFileSync, mkdirSync } from "node:fs";
import path from "node:path";
import { run, one, tx, seed, db } from "../server/db.js";
const args = Object.fromEntries(
  process.argv.slice(2).map((x) => {
    const i = x.indexOf("=");
    return [x.slice(0, i), x.slice(i + 1)];
  }),
);
if (!args.email || !args.business || !args.name || !args.output)
  throw new Error(
    'Required: email=admin@example.com business="Business" name="Administrator" output=private-credentials.json [sample=yes]',
  );
if (!/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(args.email))
  throw new Error("Valid email required.");
const password = crypto.randomBytes(24).toString("base64url"),
  recovery = crypto.randomBytes(18).toString("hex"),
  salt = crypto.randomBytes(16).toString("hex");
const passwordHash =
  salt + ":" + crypto.scryptSync(password, salt, 64).toString("hex");
const output = path.resolve(args.output);
mkdirSync(path.dirname(output), { recursive: true, mode: 0o700 });
tx(() => {
  if (one("SELECT id FROM users WHERE email=?", args.email.toLowerCase()))
    throw new Error("Account already exists.");
  const tenant = Number(
    run(
      "INSERT INTO tenants(name,demo) VALUES(?,?)",
      args.business,
      args.sample === "yes" ? 1 : 0,
    ).lastInsertRowid,
  );
  run(
    "INSERT INTO users(tenant,name,email,password,role,recovery) VALUES(?,?,?,?,?,?)",
    tenant,
    args.name,
    args.email.toLowerCase(),
    passwordHash,
    "admin",
    crypto.createHash("sha256").update(recovery).digest("hex"),
  );
  if (args.sample === "yes") seed(tenant);
  writeFileSync(
    output,
    JSON.stringify({ email: args.email, password, recovery }, null, 2),
    { mode: 0o600, flag: "wx" },
  );
});
db.close();
console.log(
  "Administrator provisioned. Credentials saved only in the specified private file.",
);
