/**
 * Unit tests for src/utils/delegationCrypto.ts
 */

import {
  signDelegationPayload,
  verifyDelegationSignature,
  generateDelegationToken,
} from '../../../src/utils/delegationCrypto';
import { DelegationTokenPayload } from '../../../src/types/delegation';

const MOCK_PAYLOAD: DelegationTokenPayload = {
  chainId: 'chain-uuid-1234',
  tenantId: 'org_system',
  delegatorAgentId: 'delegator-uuid',
  delegateeAgentId: 'delegatee-uuid',
  scopes: ['agents:read', 'tokens:read'],
  issuedAt: '2026-04-03T00:00:00.000Z',
  expiresAt: '2026-04-03T01:00:00.000Z',
};

const SECRET = 'test-hmac-secret';

describe('delegationCrypto', () => {
  describe('signDelegationPayload', () => {
    it('returns a non-empty hex string', () => {
      const sig = signDelegationPayload(MOCK_PAYLOAD, SECRET);
      expect(typeof sig).toBe('string');
      expect(sig.length).toBeGreaterThan(0);
      // SHA-256 hex = 64 chars
      expect(sig).toMatch(/^[0-9a-f]{64}$/);
    });

    it('produces the same signature for the same payload and secret', () => {
      const sig1 = signDelegationPayload(MOCK_PAYLOAD, SECRET);
      const sig2 = signDelegationPayload(MOCK_PAYLOAD, SECRET);
      expect(sig1).toBe(sig2);
    });

    it('produces different signatures for different secrets', () => {
      const sig1 = signDelegationPayload(MOCK_PAYLOAD, 'secret-a');
      const sig2 = signDelegationPayload(MOCK_PAYLOAD, 'secret-b');
      expect(sig1).not.toBe(sig2);
    });

    it('produces different signatures for different payloads', () => {
      const payload2 = { ...MOCK_PAYLOAD, chainId: 'different-chain-uuid' };
      const sig1 = signDelegationPayload(MOCK_PAYLOAD, SECRET);
      const sig2 = signDelegationPayload(payload2, SECRET);
      expect(sig1).not.toBe(sig2);
    });
  });

  describe('verifyDelegationSignature', () => {
    it('returns true for a valid sign/verify round-trip', () => {
      const signature = signDelegationPayload(MOCK_PAYLOAD, SECRET);
      expect(verifyDelegationSignature(MOCK_PAYLOAD, signature, SECRET)).toBe(true);
    });

    it('returns false when the payload has been tampered with', () => {
      const signature = signDelegationPayload(MOCK_PAYLOAD, SECRET);
      const tampered = { ...MOCK_PAYLOAD, scopes: ['admin:orgs'] };
      expect(verifyDelegationSignature(tampered, signature, SECRET)).toBe(false);
    });

    it('returns false when the secret does not match', () => {
      const signature = signDelegationPayload(MOCK_PAYLOAD, SECRET);
      expect(verifyDelegationSignature(MOCK_PAYLOAD, signature, 'wrong-secret')).toBe(false);
    });

    it('returns false for an empty signature string', () => {
      expect(verifyDelegationSignature(MOCK_PAYLOAD, '', SECRET)).toBe(false);
    });
  });

  describe('generateDelegationToken', () => {
    it('returns a UUID v4 string', () => {
      const token = generateDelegationToken();
      expect(token).toMatch(
        /^[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i,
      );
    });

    it('generates unique tokens on each call', () => {
      const tokens = new Set(Array.from({ length: 50 }, () => generateDelegationToken()));
      expect(tokens.size).toBe(50);
    });
  });
});
