/**
 * @bytelyst/field-encrypt — In-memory key provider
 *
 * For unit tests — no external dependencies.
 * Generates a random MEK on instantiation. Wrapping is just XOR for simplicity in tests,
 * but uses AES-256-GCM to match production semantics.
 */

import { createCipheriv, createDecipheriv, randomBytes } from 'node:crypto';
import type { KeyProvider } from './types.js';

const ALGORITHM = 'aes-256-gcm';
const IV_BYTES = 12;

export class MemoryKeyProvider implements KeyProvider {
  private readonly mek: Buffer;
  private readonly version: string;

  constructor(mek?: Buffer, version?: string) {
    this.mek = mek ?? randomBytes(32);
    this.version = version ?? 'memory-v1';
  }

  async wrapKey(dek: Buffer): Promise<{ wrappedKey: string; mekVersion: string }> {
    const iv = randomBytes(IV_BYTES);
    const cipher = createCipheriv(ALGORITHM, this.mek, iv);
    let encrypted = cipher.update(dek);
    encrypted = Buffer.concat([encrypted, cipher.final()]);
    const tag = cipher.getAuthTag();

    // Format: iv (12) + tag (16) + ciphertext
    const wrapped = Buffer.concat([iv, tag, encrypted]);
    return { wrappedKey: wrapped.toString('hex'), mekVersion: this.version };
  }

  async unwrapKey(wrappedKeyHex: string, _mekVersion: string): Promise<Buffer> {
    const wrapped = Buffer.from(wrappedKeyHex, 'hex');
    const iv = wrapped.subarray(0, IV_BYTES);
    const tag = wrapped.subarray(IV_BYTES, IV_BYTES + 16);
    const ciphertext = wrapped.subarray(IV_BYTES + 16);

    const decipher = createDecipheriv(ALGORITHM, this.mek, iv);
    decipher.setAuthTag(tag);
    let decrypted = decipher.update(ciphertext);
    decrypted = Buffer.concat([decrypted, decipher.final()]);
    return decrypted;
  }
}
