import { cifrar, descifrar, enmascarar, firmaCoincide } from './cifrado.util';

const CLAVE = 'a'.repeat(32);

describe('cifrado.util', () => {
  it('ida y vuelta devuelve el original', () => {
    const secreto = JSON.stringify({ access_token: 'EAAG...xyz', app_secret: 's3cr3t' });
    expect(descifrar(cifrar(secreto, CLAVE, 'X_KEY'), CLAVE, 'X_KEY')).toBe(secreto);
  });

  /** Si el IV se reutilizara, dos credenciales iguales se verían iguales en base. */
  it('cifrar dos veces lo mismo da resultados distintos', () => {
    expect(cifrar('hola', CLAVE, 'X_KEY')).not.toBe(cifrar('hola', CLAVE, 'X_KEY'));
  });

  it('el formato es iv:dato en hex', () => {
    const [iv, dato] = cifrar('hola', CLAVE, 'X_KEY').split(':');
    expect(iv).toMatch(/^[0-9a-f]{32}$/);
    expect(dato).toMatch(/^[0-9a-f]+$/);
  });

  it('una clave de largo incorrecto falla nombrando la variable', () => {
    expect(() => cifrar('hola', 'corta', 'CRM_ENCRYPTION_KEY')).toThrow(/CRM_ENCRYPTION_KEY/);
  });

  it('con otra clave no se puede descifrar', () => {
    const c = cifrar('hola', CLAVE, 'X_KEY');
    expect(() => descifrar(c, 'b'.repeat(32), 'X_KEY')).toThrow();
  });

  it('un dato sin el separador se rechaza con un mensaje claro', () => {
    expect(() => descifrar('solotexto', CLAVE, 'X_KEY')).toThrow(/formato/i);
  });

  describe('enmascarar', () => {
    it('tapa el secreto dejando puntas reconocibles', () => {
      expect(enmascarar('EAAGabcdef1234567890xyz')).toBe('EAAGab…0xyz');
    });

    /** Mostrar 8 de 12 caracteres es casi mostrarlo. */
    it('un secreto corto se tapa entero', () => {
      expect(enmascarar('123456789012')).toBe('••••');
    });

    it('sin valor devuelve null', () => {
      expect(enmascarar(null)).toBeNull();
      expect(enmascarar('')).toBeNull();
    });
  });

  describe('firmaCoincide', () => {
    it('acepta firmas iguales', () => {
      expect(firmaCoincide('abc123', 'abc123')).toBe(true);
    });

    it('rechaza firmas distintas', () => {
      expect(firmaCoincide('abc123', 'abc124')).toBe(false);
    });

    /** timingSafeEqual explota con largos distintos: hay que cortar antes. */
    it('largos distintos devuelven false, no excepción', () => {
      expect(firmaCoincide('abc', 'abcdef')).toBe(false);
      expect(firmaCoincide('', 'x')).toBe(false);
    });
  });
});
