import { describe, it, expect, beforeEach, afterEach } from 'vitest';
import { sealClientKey, unsealClientKey } from '../peer-key.util.js';

const TEST_SECRET = 'test-secret-for-peer-key-unit-tests-only';

const TEST_PEM = `-----BEGIN PRIVATE KEY-----
MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQC7o4qne60TB3wo
pCOW8QqstpxEBpnFo37JxLYEJbpE3gUlJajsHv9UWRQ7m5B7n+MBXwTCQqMEY8Wl
kHv9tGgz1YGwzBjNKxPJXE6pPTXQ1Oa0VB9l3qHdqF5HtZoJzE0c6dO8HJ5YUVL
-----END PRIVATE KEY-----`;

let savedSecret: string | undefined;

beforeEach(() => {
  savedSecret = process.env['BETTER_AUTH_SECRET'];
  process.env['BETTER_AUTH_SECRET'] = TEST_SECRET;
});

afterEach(() => {
  if (savedSecret === undefined) {
    delete process.env['BETTER_AUTH_SECRET'];
  } else {
    process.env['BETTER_AUTH_SECRET'] = savedSecret;
  }
});

describe('peer-key seal/unseal', () => {
  it('round-trip: unsealClientKey(sealClientKey(pem)) returns original pem', () => {
    const sealed = sealClientKey(TEST_PEM);
    const roundTripped = unsealClientKey(sealed);
    expect(roundTripped).toBe(TEST_PEM);
  });

  it('non-determinism: sealClientKey produces different ciphertext each call', () => {
    const sealed1 = sealClientKey(TEST_PEM);
    const sealed2 = sealClientKey(TEST_PEM);
    expect(sealed1).not.toBe(sealed2);
  });

  it('at-rest: sealed output does not contain plaintext PEM content', () => {
    const sealed = sealClientKey(TEST_PEM);
    expect(sealed).not.toContain('PRIVATE KEY');
    expect(sealed).not.toContain(
      'MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQC7o4qne60TB3wo',
    );
  });

  it('tamper: flipping a byte in the sealed payload causes unseal to throw', () => {
    const sealed = sealClientKey(TEST_PEM);
    const buf = Buffer.from(sealed, 'base64');
    // Flip a byte in the middle of the buffer (past IV and authTag)
    const midpoint = Math.floor(buf.length / 2);
    buf[midpoint] = buf[midpoint]! ^ 0xff;
    const tampered = buf.toString('base64');
    expect(() => unsealClientKey(tampered)).toThrow();
  });

  it('missing secret: unsealClientKey throws when BETTER_AUTH_SECRET is unset', () => {
    const sealed = sealClientKey(TEST_PEM);
    delete process.env['BETTER_AUTH_SECRET'];
    expect(() => unsealClientKey(sealed)).toThrow('BETTER_AUTH_SECRET is not set');
  });
});
