import { describe, it, expect } from 'vitest';
import {
  encryptAES256GCM,
  decryptAES256GCM,
  resolveMasterKey,
  generateApiKey,
  computeKeyVerifier,
  verifyApiKey,
  getMaskedApiKeyPrefix,
} from '@zyphon/crypto';

describe('Crypto Module', () => {
  const masterKey = resolveMasterKey('0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef');
  const systemPepper = 'test-system-pepper-secret';

  describe('Vault AES-256-GCM', () => {
    it('encrypts and decrypts secrets correctly', () => {
      const plaintext = JSON.stringify({
        api_key: 'sg_secret_key_12345',
        endpoint: 'https://api.sendgrid.com',
        rate_limit: 100,
      });

      const encrypted = encryptAES256GCM(plaintext, masterKey);

      expect(encrypted.ciphertext).toBeDefined();
      expect(encrypted.iv).toBeDefined();
      expect(encrypted.tag).toBeDefined();

      const decrypted = decryptAES256GCM(encrypted, masterKey);
      expect(JSON.parse(decrypted)).toEqual(JSON.parse(plaintext));
    });

    it('fails decryption with invalid or tampered ciphertext', () => {
      const plaintext = JSON.stringify({ secret: 'super_secret' });
      const encrypted = encryptAES256GCM(plaintext, masterKey);

      const tampered = {
        ...encrypted,
        ciphertext: Buffer.from('tampered_content').toString('base64'),
      };

      expect(() => decryptAES256GCM(tampered, masterKey)).toThrow();
    });

    it('fails decryption with wrong master key', () => {
      const plaintext = JSON.stringify({ secret: 'super_secret' });
      const encrypted = encryptAES256GCM(plaintext, masterKey);
      const wrongKey = resolveMasterKey('fedcba9876543210fedcba9876543210fedcba9876543210fedcba9876543210');

      expect(() => decryptAES256GCM(encrypted, wrongKey)).toThrow();
    });
  });

  describe('API Key Management', () => {
    it('generates well-formed API keys with custom prefix', () => {
      const key = generateApiKey();
      expect(key.startsWith('zy_')).toBe(true);
      expect(key.length).toBe(35); // 'zy_' (3) + 32 hex chars (32) = 35
      expect(getMaskedApiKeyPrefix(key)).toBe(key.slice(0, 7) + '...');
    });

    it('hashes and verifies valid API keys in constant time', () => {
      const apiKey = generateApiKey();
      const hash = computeKeyVerifier(apiKey, systemPepper);

      expect(verifyApiKey(apiKey, hash, systemPepper)).toBe(true);
      expect(verifyApiKey('zy_wrong_key_1234567890', hash, systemPepper)).toBe(false);
    });
  });
});

