import { describe, expect, it } from 'vitest';
import { spaceColor } from './spaceColor';

const PALETTE = [
  '#6366f1',
  '#0ea5e9',
  '#10b981',
  '#f59e0b',
  '#ef4444',
  '#ec4899',
  '#8b5cf6',
  '#14b8a6',
  '#f97316',
  '#84cc16',
];

// Reference FNV-1a (matches the implementation) to assert exact picks.
function fnv1a(str: string): number {
  let h = 0x811c9dc5;
  for (let i = 0; i < str.length; i++) {
    h ^= str.charCodeAt(i);
    h = Math.imul(h, 0x01000193) >>> 0;
  }
  return h >>> 0;
}

describe('spaceColor', () => {
  it('returns a color from the known palette', () => {
    expect(PALETTE).toContain(spaceColor('space-1'));
  });

  it('is deterministic for the same id', () => {
    expect(spaceColor('alpha')).toBe(spaceColor('alpha'));
    expect(spaceColor('a-very-long-space-identifier-123')).toBe(
      spaceColor('a-very-long-space-identifier-123'),
    );
  });

  it('matches the reference FNV-1a modulo palette length', () => {
    for (const id of ['', 'x', 'space-42', 'personal', '日本語スペース']) {
      const expected = PALETTE[fnv1a(id) % PALETTE.length];
      expect(spaceColor(id)).toBe(expected);
    }
  });

  it('handles the empty string deterministically and within the palette', () => {
    const c = spaceColor('');
    expect(PALETTE).toContain(c);
    expect(spaceColor('')).toBe(c);
  });

  it('handles unicode ids', () => {
    const c = spaceColor('案件スペース🎨');
    expect(PALETTE).toContain(c);
  });

  it('produces different colors for at least some different ids (distribution)', () => {
    const ids = Array.from({ length: 50 }, (_, i) => `space-${i}`);
    const colors = new Set(ids.map(spaceColor));
    // With 50 ids over 10 buckets, expect most/all buckets to be hit.
    expect(colors.size).toBeGreaterThan(1);
    for (const c of colors) expect(PALETTE).toContain(c);
  });

  it('always returns a 7-char hex string', () => {
    for (const id of ['', 'a', 'space-9999', 'Z']) {
      expect(spaceColor(id)).toMatch(/^#[0-9a-f]{6}$/);
    }
  });
});
