/**
 * Creates an admin user, or resets an existing user's password.
 *
 *   npm run admin:create
 *   npm run admin:create -- --email you@example.com --name "Your Name" --role ADMIN
 *
 * The password is read from ADMIN_PASSWORD or prompted for (input hidden),
 * never taken from the command line where it would land in shell history.
 */
import { stdin, stdout } from "node:process";
import { createInterface } from "node:readline/promises";
import { parseArgs } from "node:util";

import { PASSWORD_MAX_LENGTH, PASSWORD_MIN_LENGTH } from "../src/lib/auth/constants";
import { hashPassword } from "../src/lib/auth/password";

import { createScriptClient } from "./prisma-client";

async function prompt(question: string, { hidden = false } = {}) {
  const rl = createInterface({ input: stdin, output: stdout, terminal: true });
  if (hidden) {
    // Mask typed characters.
    const write = (rl as unknown as { _writeToOutput: (text: string) => void })._writeToOutput;
    (rl as unknown as { _writeToOutput: (text: string) => void })._writeToOutput = (text) => {
      write.call(rl, text.startsWith(question) ? text : "*".repeat(text.length ? 1 : 0));
    };
  }
  const answer = await rl.question(question);
  rl.close();
  if (hidden) stdout.write("\n");
  return answer.trim();
}

async function main() {
  const { values } = parseArgs({
    options: {
      email: { type: "string" },
      name: { type: "string" },
      role: { type: "string", default: "ADMIN" },
    },
  });

  const email = (values.email ?? (await prompt("Email: "))).toLowerCase();
  if (!/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(email)) throw new Error("Enter a valid email address.");

  const role = values.role?.toUpperCase() === "EDITOR" ? "EDITOR" : "ADMIN";
  const db = createScriptClient();

  try {
    const existing = await db.adminUser.findUnique({ where: { email } });
    const name = values.name ?? existing?.name ?? (await prompt("Name: "));
    if (!name) throw new Error("Enter a name.");

    const password = process.env.ADMIN_PASSWORD ?? (await prompt("Password: ", { hidden: true }));
    if (password.length < PASSWORD_MIN_LENGTH || password.length > PASSWORD_MAX_LENGTH) {
      throw new Error(`Passwords must be ${PASSWORD_MIN_LENGTH}–${PASSWORD_MAX_LENGTH} characters.`);
    }

    const passwordHash = await hashPassword(password);
    if (existing) {
      await db.adminUser.update({
        where: { id: existing.id },
        data: { name, passwordHash, role, isActive: true },
      });
      await db.adminSession.deleteMany({ where: { userId: existing.id } });
      console.log(`Updated ${email} (${role}). Existing sessions were signed out.`);
    } else {
      await db.adminUser.create({ data: { email, name, passwordHash, role } });
      console.log(`Created ${email} (${role}). Sign in at /login.`);
    }
  } finally {
    await db.$disconnect();
  }
}

main().catch((error: unknown) => {
  console.error(error instanceof Error ? error.message : error);
  process.exit(1);
});
