import {
  describe,
  it,
  expect
} from 'vitest';
import {
  rankFeaturedServers,
  rankTrendingServers,
  RankableServer
} from './server-ranking.util';

function server(id: string, lastSeen: number): RankableServer {
  return { id, lastSeen };
}

describe('rankFeaturedServers', () => {
  it('orders by membership count descending', () => {
    const rows = [
      server('a', 100),
      server('b', 100),
      server('c', 100)
    ];
    const counts = new Map([
      ['a', 2],
      ['b', 10],
      ['c', 5]
    ]);
    const ranked = rankFeaturedServers(rows, counts);

    expect(ranked.map((row) => row.id)).toEqual([
      'b',
      'c',
      'a'
    ]);
  });

  it('breaks membership ties by most recent activity', () => {
    const rows = [
      server('a', 50),
      server('b', 200),
      server('c', 120)
    ];
    const counts = new Map([
      ['a', 5],
      ['b', 5],
      ['c', 5]
    ]);
    const ranked = rankFeaturedServers(rows, counts);

    expect(ranked.map((row) => row.id)).toEqual([
      'b',
      'c',
      'a'
    ]);
  });

  it('treats missing counts as zero', () => {
    const rows = [server('a', 10), server('b', 10)];
    const counts = new Map([['a', 1]]);
    const ranked = rankFeaturedServers(rows, counts);

    expect(ranked.map((row) => row.id)).toEqual(['a', 'b']);
  });

  it('applies the limit', () => {
    const rows = [
      server('a', 1),
      server('b', 2),
      server('c', 3)
    ];
    const counts = new Map([
      ['a', 3],
      ['b', 2],
      ['c', 1]
    ]);

    expect(rankFeaturedServers(rows, counts, 2).map((row) => row.id)).toEqual(['a', 'b']);
  });

  it('returns an empty array for a non-positive limit', () => {
    const rows = [server('a', 1)];

    expect(rankFeaturedServers(rows, new Map(), 0)).toEqual([]);
    expect(rankFeaturedServers(rows, new Map(), -5)).toEqual([]);
  });

  it('does not mutate the input rows', () => {
    const rows = [server('a', 1), server('b', 2)];

    rankFeaturedServers(rows, new Map([['b', 9]]));

    expect(rows.map((row) => row.id)).toEqual(['a', 'b']);
  });
});

describe('rankTrendingServers', () => {
  it('orders by most recent activity descending', () => {
    const rows = [
      server('a', 100),
      server('b', 300),
      server('c', 200)
    ];
    const counts = new Map<string, number>();
    const ranked = rankTrendingServers(rows, counts);

    expect(ranked.map((row) => row.id)).toEqual([
      'b',
      'c',
      'a'
    ]);
  });

  it('breaks activity ties by membership count', () => {
    const rows = [
      server('a', 100),
      server('b', 100),
      server('c', 100)
    ];
    const counts = new Map([
      ['a', 1],
      ['b', 9],
      ['c', 4]
    ]);
    const ranked = rankTrendingServers(rows, counts);

    expect(ranked.map((row) => row.id)).toEqual([
      'b',
      'c',
      'a'
    ]);
  });

  it('applies the limit', () => {
    const rows = [
      server('a', 1),
      server('b', 2),
      server('c', 3)
    ];

    expect(rankTrendingServers(rows, new Map(), 1).map((row) => row.id)).toEqual(['c']);
  });
});
