import { describe, expect, it } from 'vitest';
import { generateTempPassword } from './passwords';
import { JOIN_CODE_PATTERN, joinCodeCandidates, normalizeJoinCode, SLUG_PATTERN, slugify, uniqueSlug } from './venue-codes';

/** Deterministic PRNG for repeatable candidates. */
function seeded(seed: number): () => number {
  let s = seed;
  return () => {
    s = (s * 1_103_515_245 + 12_345) % 2_147_483_648;
    return s / 2_147_483_648;
  };
}

describe('slugs', () => {
  it('slugifies names', () => {
    expect(slugify('The Harbor Tap')).toBe('the-harbor-tap');
    expect(slugify('  Café Olé & Sons!! ')).toBe('cafe-ole-and-sons');
    expect(slugify('!!!')).toBe('venue');
    expect(slugify('x'.repeat(80)).length).toBeLessThanOrEqual(48);
    expect(SLUG_PATTERN.test(slugify('Ocean Ave — Pub #2'))).toBe(true);
  });

  it('suffixes taken slugs', () => {
    expect(uniqueSlug('main', new Set())).toBe('main');
    expect(uniqueSlug('main', new Set(['main', 'main-2']))).toBe('main-3');
  });
});

describe('join codes', () => {
  it('prefers the distinctive word of the name', () => {
    const list = joinCodeCandidates('The Harbor Tap', 6, seeded(1));
    expect(list[0]).toBe('HARBOR');
    expect(joinCodeCandidates('Ocean Ave Pub', 3, seeded(2))[0]).toBe('OCEAN');
    expect(joinCodeCandidates('QA Test Lounge', 3, seeded(3))[0]).toBe('TEST');
  });

  it('always returns valid, distinct codes, even for odd names', () => {
    for (const name of ['The Harbor Tap', 'Q', '', '★★★', 'Joe’s', 'Bar 42 Lounge', 'Ünïcödé Kneipe']) {
      const list = joinCodeCandidates(name, 10, seeded(7));
      expect(list.length).toBe(10);
      expect(new Set(list).size).toBe(list.length);
      for (const code of list) expect(code).toMatch(JOIN_CODE_PATTERN);
    }
  });

  it('normalises typed codes', () => {
    expect(normalizeJoinCode('  harbor ')).toBe('HARBOR');
  });
});

describe('temporary passwords', () => {
  it('are long, grouped and unambiguous', () => {
    const pw = generateTempPassword();
    expect(pw).toMatch(/^[a-zA-Z2-9]{4}(-[a-zA-Z2-9]{4}){3}$/);
    expect(pw).not.toMatch(/[01OIl]/);
    expect(generateTempPassword()).not.toBe(pw);
    expect(() => generateTempPassword(4)).toThrow();
  });
});
