// apps/web/src/server/crypto/invoice-credentials.ts
// AES-GCM encryption/decryption for vendor invoice provider credentials.
// INVOICE_KEK is a CF Worker binding (secret), 32 random bytes, base64url-encoded.

export async function encryptCredentials(plaintext: string, kek: string): Promise<{ ciphertext: string; iv: string; tag: string }> {
  const key = await crypto.subtle.importKey(
    'raw', Buffer.from(kek, 'base64'), { name: 'AES-GCM' }, false, ['encrypt'],
  );
  const iv = crypto.getRandomValues(new Uint8Array(12));
  const enc = new TextEncoder();
  const cipherBuf = await crypto.subtle.encrypt({ name: 'AES-GCM', iv }, key, enc.encode(plaintext));
  const cipher = new Uint8Array(cipherBuf);
  // AES-GCM appends 16-byte tag at end of ciphertext
  const ciphertext = Buffer.from(cipher.slice(0, -16)).toString('base64');
  const tag = Buffer.from(cipher.slice(-16)).toString('base64');
  return { ciphertext, iv: Buffer.from(iv).toString('base64'), tag };
}

export async function decryptCredentials(args: { ciphertext: string; iv: string; tag: string }, kek: string): Promise<string> {
  const key = await crypto.subtle.importKey(
    'raw', Buffer.from(kek, 'base64'), { name: 'AES-GCM' }, false, ['decrypt'],
  );
  const cipherBytes = Buffer.from(args.ciphertext, 'base64');
  const tagBytes = Buffer.from(args.tag, 'base64');
  const combined = new Uint8Array(cipherBytes.length + tagBytes.length);
  combined.set(cipherBytes);
  combined.set(tagBytes, cipherBytes.length);
  const ivBytes = Buffer.from(args.iv, 'base64');
  const plain = await crypto.subtle.decrypt({ name: 'AES-GCM', iv: ivBytes }, key, combined);
  return new TextDecoder().decode(plain);
}
