import "dotenv/config";
import { decryptWithKey, encryptWithKey } from "../src/utils/encryption";
// Shared adapter-wired client (Prisma 7 needs a driver adapter).
import prisma from "../src/config/database";

// Reuse the dual-format decrypt/encrypt from src/utils/encryption.ts so this
// script handles BOTH wire formats: the TS `hex:hex:hex` form and the
// PHP-legacy single-base64 blob. The previous hand-rolled `decrypt` only parsed
// the TS form and threw `Buffer.from(undefined, 'hex')` on any legacy secret —
// inside the $transaction that aborted/rolled back the ENTIRE batch on the first
// legacy user. These key-parameterized helpers accept the old/new keys passed on
// the command line (the config-bound `decrypt`/`encrypt` use the env key only).
const decrypt = (ciphertext: string, keyHex: string): string =>
  decryptWithKey(ciphertext, keyHex);
const encrypt = (plaintext: string, keyHex: string): string =>
  encryptWithKey(plaintext, keyHex);

async function main() {
  const oldKey = process.argv[2];
  const newKey = process.argv[3];
  const dryRun = process.argv.includes("--dry-run");

  if (!oldKey || !newKey) {
    console.error(
      "Usage: tsx scripts/rotate-totp-key.ts <old-key-hex> <new-key-hex> [--dry-run]",
    );
    process.exit(1);
  }

  const users = await prisma.users.findMany({
    where: { totp_enabled: true, totp_secret: { not: null } },
    select: { id: true, username: true, totp_secret: true },
  });

  console.log(`Found ${users.length} users with TOTP enabled`);

  if (dryRun) {
    for (const user of users) {
      try {
        const decrypted = decrypt(user.totp_secret!, oldKey);
        const reEncrypted = encrypt(decrypted, newKey);
        decrypt(reEncrypted, newKey); // verify round-trip
        console.log(
          `  [OK] ${user.username} (id=${user.id}) — decryption and re-encryption verified`,
        );
      } catch (e) {
        console.error(`  [FAIL] ${user.username} (id=${user.id}) — ${e}`);
      }
    }
    console.log("\nDry run complete. No changes made.");
    return;
  }

  await prisma.$transaction(async (tx) => {
    for (const user of users) {
      const decrypted = decrypt(user.totp_secret!, oldKey);
      const reEncrypted = encrypt(decrypted, newKey);
      await tx.users.update({
        where: { id: user.id },
        data: { totp_secret: reEncrypted },
      });
      console.log(`  Re-encrypted TOTP for ${user.username} (id=${user.id})`);
    }
  });

  console.log("\nAll TOTP secrets re-encrypted successfully.");
  await prisma.$disconnect();
}

main().catch((e) => {
  console.error(e);
  process.exit(1);
});
