/**
 * Tests for cryptographic utilities
 */

import { generateEncryptionKey, exportKey, importKey, encrypt, decrypt } from '../src/utils/crypto';

describe('Crypto utilities', () => {
  test('should generate encryption key', async () => {
    const key = await generateEncryptionKey();
    expect(key).toBeDefined();
    expect(key.type).toBe('secret');
  });

  test('should export and import key', async () => {
    const key = await generateEncryptionKey();
    const exported = await exportKey(key);
    expect(typeof exported).toBe('string');
    expect(exported.length).toBeGreaterThan(0);

    const imported = await importKey(exported);
    expect(imported).toBeDefined();
    expect(imported.type).toBe('secret');
  });

  test('should encrypt and decrypt data', async () => {
    const key = await generateEncryptionKey();
    const plaintext = 'test data';

    const encrypted = await encrypt(plaintext, key);
    expect(encrypted.ciphertext).toBeDefined();
    expect(encrypted.iv).toBeDefined();
    expect(encrypted.ciphertext).not.toBe(plaintext);

    const decrypted = await decrypt(encrypted, key);
    expect(decrypted).toBe(plaintext);
  });

  test('should encrypt same data differently each time (different IV)', async () => {
    const key = await generateEncryptionKey();
    const plaintext = 'test data';

    const encrypted1 = await encrypt(plaintext, key);
    const encrypted2 = await encrypt(plaintext, key);

    expect(encrypted1.ciphertext).not.toBe(encrypted2.ciphertext);
    expect(encrypted1.iv).not.toBe(encrypted2.iv);

    const decrypted1 = await decrypt(encrypted1, key);
    const decrypted2 = await decrypt(encrypted2, key);

    expect(decrypted1).toBe(plaintext);
    expect(decrypted2).toBe(plaintext);
  });

  test('should fail to decrypt with wrong key', async () => {
    const key1 = await generateEncryptionKey();
    const key2 = await generateEncryptionKey();
    const plaintext = 'test data';

    const encrypted = await encrypt(plaintext, key1);

    await expect(decrypt(encrypted, key2)).rejects.toThrow();
  });
});
