import { config } from "dotenv";
import path from "node:path";
import { randomBytes } from "node:crypto";
config({ path: path.resolve(process.cwd(), ".env.local") });
config({ path: path.resolve(process.cwd(), ".env") });

/**
 * Reconciles the admin roster so only Prof Mohamed A. Imam and Atef A.
 * Hassan have the `admin` role. Everyone else is demoted to `user`.
 *
 * If Prof Imam's account is missing, it's created as an active admin with a
 * random 48-char temporary password. The temporary password is printed once
 * and the admin can issue a password reset from `/admin/members` afterwards.
 */

const ADMIN_ROSTER = [
  {
    email: "atefabdo26399@gmail.com",
    name: "Atef A. Hassan",
    professionalRole: "researcher",
  },
  {
    email: "atef@orthoglobe.org",
    name: "Atef A. Hassan",
    professionalRole: "researcher",
  },
  {
    email: "imam@orthoglobe.org",
    name: "Prof Mohamed A. Imam",
    professionalRole: "consultant",
  },
];

async function main() {
  if (!process.env.DATABASE_URL) throw new Error("DATABASE_URL not set");

  const postgres = (await import("postgres")).default;
  const { drizzle } = await import("drizzle-orm/postgres-js");
  const { eq, notInArray, and } = await import("drizzle-orm");
  const { hash } = await import("@node-rs/argon2");
  const schema = await import("../src/lib/db/schema");

  const sql = postgres(process.env.DATABASE_URL!, { max: 1 });
  const db = drizzle(sql, { schema });

  const rosterEmails = ADMIN_ROSTER.map((a) => a.email.toLowerCase());
  const tempPasswords: Array<{ email: string; tempPassword: string }> = [];

  for (const adminDef of ADMIN_ROSTER) {
    const [existing] = await db
      .select()
      .from(schema.users)
      .where(eq(schema.users.email, adminDef.email.toLowerCase()))
      .limit(1);

    if (existing) {
      if (existing.role !== "admin" || existing.status !== "active") {
        await db
          .update(schema.users)
          .set({
            role: "admin",
            status: "active",
            name: adminDef.name,
            approvedAt: existing.approvedAt ?? new Date(),
          })
          .where(eq(schema.users.id, existing.id));
        console.log(`promoted: ${adminDef.email}`);
      } else {
        // Refresh the name in case of a rename (e.g. "Atef Hassan" → "Atef A. Hassan").
        if (existing.name !== adminDef.name) {
          await db
            .update(schema.users)
            .set({ name: adminDef.name })
            .where(eq(schema.users.id, existing.id));
          console.log(`renamed: ${adminDef.email} → ${adminDef.name}`);
        } else {
          console.log(`ok: ${adminDef.email}`);
        }
      }
    } else {
      const tempPassword = randomBytes(24).toString("base64url");
      const passwordHash = await hash(tempPassword, {
        memoryCost: 19_456,
        timeCost: 2,
        parallelism: 1,
      });
      await db.insert(schema.users).values({
        email: adminDef.email.toLowerCase(),
        name: adminDef.name,
        country: "United Kingdom",
        institution: "OrthoGlobe",
        professionalRole: adminDef.professionalRole,
        passwordHash,
        status: "active",
        role: "admin",
        approvedAt: new Date(),
      });
      tempPasswords.push({ email: adminDef.email, tempPassword });
      console.log(`created: ${adminDef.email}`);
    }
  }

  // Demote every other admin to user. Leaves status alone.
  const demoted = await db
    .update(schema.users)
    .set({ role: "user" })
    .where(
      and(
        eq(schema.users.role, "admin"),
        notInArray(schema.users.email, rosterEmails),
      ),
    )
    .returning({ email: schema.users.email });

  for (const d of demoted) console.log(`demoted to user: ${d.email}`);

  // Final roster report.
  const rows = await db
    .select({
      email: schema.users.email,
      name: schema.users.name,
      status: schema.users.status,
      role: schema.users.role,
    })
    .from(schema.users)
    .orderBy(schema.users.role, schema.users.email);

  console.log("\nFinal user roster:");
  console.table(rows);

  if (tempPasswords.length > 0) {
    console.log("\n⚠️  Newly created admins with TEMPORARY passwords:");
    for (const t of tempPasswords) {
      console.log(`  ${t.email}  →  ${t.tempPassword}`);
    }
    console.log(
      "\nAsk each admin to sign in with the temp password above, then change it at /account/security",
    );
    console.log(
      "Or open /admin/members and click \"Send password reset\" to email them a reset link.",
    );
  }

  await sql.end();
}

main()
  .then(() => process.exit(0))
  .catch((err) => {
    console.error(err);
    process.exit(1);
  });
