import { deriveUniqueShortCode } from './short-code';

describe('deriveUniqueShortCode', () => {
  const never = async () => false;

  it('returns first 6 alphanumeric chars uppercased', async () => {
    expect(await deriveUniqueShortCode('Atlantis The Palm', 'HTL', never)).toBe('ATLANT');
  });

  it('strips punctuation, spaces, and accents (non-alphanumeric)', async () => {
    expect(await deriveUniqueShortCode('Burj  Al-Arab!', 'HTL', never)).toBe('BURJAL');
  });

  it('falls back to the prefix when the cleaned source is empty', async () => {
    expect(await deriveUniqueShortCode('   ---   ', 'DEST', never)).toBe('DEST');
    expect(await deriveUniqueShortCode(null, 'TRIP', never)).toBe('TRIP');
    expect(await deriveUniqueShortCode(undefined, 'ACT', never)).toBe('ACT');
  });

  it('respects the maxLen cap', async () => {
    expect(await deriveUniqueShortCode('Mountain', 'DEST', never, 4)).toBe('MOUN');
  });

  it('appends numeric suffix on collision (1, 2, 3 …)', async () => {
    const taken = new Set(['ATLANT', 'ATLANT1']);
    const result = await deriveUniqueShortCode('Atlantis The Palm', 'HTL', async (c) =>
      taken.has(c),
    );
    expect(result).toBe('ATLANT2');
  });

  it('suffix starts from base when the original is free', async () => {
    const taken = new Set<string>();
    const result = await deriveUniqueShortCode('Coral', 'HTL', async (c) => taken.has(c));
    expect(result).toBe('CORAL');
  });

  it('throws after 999 unsuccessful attempts (safety cap)', async () => {
    const alwaysTaken = async () => true;
    await expect(deriveUniqueShortCode('Dubai', 'DEST', alwaysTaken)).rejects.toThrow(
      /could not find a unique code/,
    );
  });

  it('handles digits in source', async () => {
    expect(await deriveUniqueShortCode('Hotel 24Seven', 'HTL', never)).toBe('HOTEL2');
  });
});
