import { describe, test, expect } from 'bun:test';
import * as fc from 'fast-check';
import {
  generateRequestId,
  generateIdempotencyKey,
  base64UrlEncode,
  base64UrlDecode,
  RequestIdSchema,
} from '../../src/index.js';

describe('generateRequestId', () => {
  test('produces 22-char base64url string', () => {
    const id = generateRequestId();
    expect(id.length).toBe(22);
    expect(RequestIdSchema.safeParse(id).success).toBe(true);
  });

  test('1e5 generated IDs are all unique', () => {
    const seen = new Set<string>();
    for (let i = 0; i < 100_000; i++) {
      const id = generateRequestId();
      expect(seen.has(id)).toBe(false);
      seen.add(id);
    }
    expect(seen.size).toBe(100_000);
  });

  test('generateIdempotencyKey returns the same shape', () => {
    expect(generateIdempotencyKey().length).toBe(22);
  });
});

describe('base64url encode/decode', () => {
  test('roundtrip arbitrary bytes (property-based)', () => {
    fc.assert(
      fc.property(fc.uint8Array({ minLength: 0, maxLength: 64 }), (bytes) => {
        const decoded = base64UrlDecode(base64UrlEncode(bytes));
        expect(decoded).toEqual(bytes);
      }),
      { numRuns: 500 },
    );
  });

  test('produces URL-safe alphabet only', () => {
    fc.assert(
      fc.property(fc.uint8Array({ minLength: 1, maxLength: 64 }), (bytes) => {
        const enc = base64UrlEncode(bytes);
        expect(enc).not.toMatch(/[+/=]/);
      }),
      { numRuns: 200 },
    );
  });

  test('handles empty input', () => {
    expect(base64UrlEncode(new Uint8Array(0))).toBe('');
    expect(base64UrlDecode('')).toEqual(new Uint8Array(0));
  });

  test('decodes inputs without padding correctly', () => {
    expect(base64UrlDecode('YQ')).toEqual(new Uint8Array([0x61]));
    expect(base64UrlDecode('YWI')).toEqual(new Uint8Array([0x61, 0x62]));
    expect(base64UrlDecode('YWJj')).toEqual(new Uint8Array([0x61, 0x62, 0x63]));
  });
});
