#!/usr/bin/env node
/**
 * Test script: Verify we can decrypt Stripe keys from D1 using APP_SK + BLOCKLET_DID (COMPONENT_DID).
 *
 * Usage:
 *   1. First, get the encrypted value from D1:
 *      wrangler d1 execute payment-kit-prod --remote \
 *        --command "SELECT settings FROM payment_methods WHERE type='stripe'" --json
 *
 *   2. Run this script with the encrypted value and keys:
 *      APP_SK=<hex> BLOCKLET_DID=<did> ENCRYPTED=<base64> node test-decrypt.js
 *
 * The decryption chain:
 *   passphrase = PBKDF2(APP_SK, BLOCKLET_DID, 256 iterations, 32 bytes, sha512).toString('hex')
 *   plaintext  = CryptoJS.AES.decrypt(encrypted, passphrase)
 *
 * CryptoJS.AES with a string passphrase uses OpenSSL's EvpKDF internally:
 *   - Input: "Salted__" + 8-byte salt + ciphertext (Base64 decoded)
 *   - EvpKDF derives key (32 bytes) + IV (16 bytes) from passphrase + salt using MD5
 *   - AES-256-CBC decryption
 */

const crypto = require('crypto');

const APP_SK = process.env.APP_SK;
const BLOCKLET_DID = process.env.BLOCKLET_DID;
const ENCRYPTED = process.env.ENCRYPTED;

if (!APP_SK || !BLOCKLET_DID || !ENCRYPTED) {
  console.log('Usage: APP_SK=<hex> BLOCKLET_DID=<did> ENCRYPTED=<base64> node test-decrypt.js');
  console.log('\nTo get ENCRYPTED value:');
  console.log('  wrangler d1 execute payment-kit-prod --remote \\');
  console.log('    --command "SELECT settings FROM payment_methods WHERE type=\'stripe\'" --json');
  process.exit(1);
}

// Step 1: Derive passphrase via PBKDF2 (same as @blocklet/sdk/lib/security)
const passphrase = crypto.pbkdf2Sync(APP_SK, BLOCKLET_DID, 256, 32, 'sha512').toString('hex');
console.log('Derived passphrase (first 16 chars):', passphrase.substring(0, 16) + '...');

// Step 2: Decode CryptoJS OpenSSL format
const rawCipher = Buffer.from(ENCRYPTED, 'base64');
const prefix = rawCipher.slice(0, 8).toString('utf8');  // Should be "Salted__"
if (prefix !== 'Salted__') {
  console.error('ERROR: Not a CryptoJS OpenSSL encrypted value (missing Salted__ prefix)');
  console.log('Raw prefix bytes:', rawCipher.slice(0, 8));
  process.exit(1);
}
console.log('Format: CryptoJS OpenSSL (Salted__)');

const salt = rawCipher.slice(8, 16);
const ciphertext = rawCipher.slice(16);
console.log('Salt (hex):', salt.toString('hex'));
console.log('Ciphertext length:', ciphertext.length, 'bytes');

// Step 3: EvpKDF — CryptoJS uses MD5-based key derivation (OpenSSL EVP_BytesToKey)
function evpKDF(password, salt, keySize, ivSize) {
  const passBuffer = Buffer.from(password, 'utf8');
  const totalSize = keySize + ivSize;
  const derived = [];
  let block = Buffer.alloc(0);

  while (Buffer.concat(derived).length < totalSize) {
    const hasher = crypto.createHash('md5');
    hasher.update(block);
    hasher.update(passBuffer);
    hasher.update(salt);
    block = hasher.digest();
    derived.push(block);
  }

  const all = Buffer.concat(derived);
  return {
    key: all.slice(0, keySize),
    iv: all.slice(keySize, keySize + ivSize),
  };
}

const { key, iv } = evpKDF(passphrase, salt, 32, 16);
console.log('AES key (hex, first 16 chars):', key.toString('hex').substring(0, 16) + '...');
console.log('AES IV (hex):', iv.toString('hex'));

// Step 4: AES-256-CBC decrypt
try {
  const decipher = crypto.createDecipheriv('aes-256-cbc', key, iv);
  let decrypted = decipher.update(ciphertext, undefined, 'utf8');
  decrypted += decipher.final('utf8');
  console.log('\n✅ DECRYPTED:', decrypted);

  // Mask sensitive output
  if (decrypted.startsWith('sk_')) {
    console.log('(Stripe secret key detected — first 12 chars: ' + decrypted.substring(0, 12) + '...)');
  } else if (decrypted.startsWith('whsec_')) {
    console.log('(Stripe webhook secret detected — first 10 chars: ' + decrypted.substring(0, 10) + '...)');
  }
} catch (err) {
  console.error('\n❌ DECRYPTION FAILED:', err.message);
  console.log('\nPossible causes:');
  console.log('  1. Wrong APP_SK — verify it matches the Blocklet Server environment');
  console.log('  2. Wrong BLOCKLET_DID — should be COMPONENT_DID (z2qa...), not APP_PID');
  console.log('  3. Data was encrypted with a different key');
}
