import { describe, it, expect } from 'vitest';
import { credKeyFromEnv, sealSecret, openSecret, SECRET_KEY_VERSION } from './secret-crypto';

const KEY = Buffer.alloc(32, 7); // deterministic 32-byte key for tests

describe('secret-crypto', () => {
  it('round-trips a secret through seal → open', () => {
    const sealed = sealSecret('sk_live_abc123', KEY);
    expect(sealed.keyVersion).toBe(SECRET_KEY_VERSION);
    expect(sealed.cipherText).not.toContain('sk_live_abc123');
    expect(openSecret(sealed, KEY)).toBe('sk_live_abc123');
  });

  it('produces a distinct ciphertext each time (random IV)', () => {
    const a = sealSecret('same', KEY);
    const b = sealSecret('same', KEY);
    expect(a.cipherText).not.toBe(b.cipherText);
    expect(a.iv).not.toBe(b.iv);
  });

  it('fails to open with the wrong key', () => {
    const sealed = sealSecret('top-secret', KEY);
    expect(() => openSecret(sealed, Buffer.alloc(32, 9))).toThrow();
  });

  it('fails to open if the ciphertext is tampered (GCM auth)', () => {
    const sealed = sealSecret('top-secret', KEY);
    const bad = { ...sealed, cipherText: Buffer.from('deadbeef', 'hex').toString('base64') };
    expect(() => openSecret(bad, KEY)).toThrow();
  });

  it('credKeyFromEnv returns null when unset and rejects a wrong-length key', () => {
    expect(credKeyFromEnv({})).toBeNull();
    expect(() => credKeyFromEnv({ IIOS_CRED_KEY: Buffer.alloc(16).toString('base64') })).toThrow(/32 bytes/);
    const key = credKeyFromEnv({ IIOS_CRED_KEY: KEY.toString('base64') });
    expect(key?.length).toBe(32);
  });
});
