import { describe, it, expect } from 'vitest';
import { rankResults } from '../../src/registry/ranking.js';
import type { RegistryServer } from '../../src/registry/types.js';

function makeServer(overrides: Partial<RegistryServer> = {}): RegistryServer {
  return {
    name: 'test-server',
    description: 'A test server',
    packages: {},
    envTemplate: [],
    transport: 'stdio',
    popularityScore: 0,
    verified: false,
    sourceRegistry: 'official',
    ...overrides,
  };
}

describe('rankResults', () => {
  it('puts exact name match first', () => {
    const servers = [
      makeServer({ name: 'slack-extended-tools' }),
      makeServer({ name: 'slack' }),
      makeServer({ name: 'my-slack-bot' }),
    ];
    const ranked = rankResults(servers, 'slack');
    expect(ranked[0]?.name).toBe('slack');
  });

  it('ranks verified servers higher than unverified', () => {
    const servers = [
      makeServer({ name: 'server-a', verified: false }),
      makeServer({ name: 'server-b', verified: true }),
    ];
    const ranked = rankResults(servers, 'server');
    expect(ranked[0]?.name).toBe('server-b');
  });

  it('ranks popular servers higher', () => {
    const servers = [
      makeServer({ name: 'unpopular', popularityScore: 1 }),
      makeServer({ name: 'popular', popularityScore: 10000 }),
    ];
    const ranked = rankResults(servers, 'test');
    expect(ranked[0]?.name).toBe('popular');
  });

  it('considers recency', () => {
    const recent = new Date();
    const old = new Date(Date.now() - 365 * 24 * 60 * 60 * 1000);
    const servers = [
      makeServer({ name: 'old-server', lastUpdated: old }),
      makeServer({ name: 'new-server', lastUpdated: recent }),
    ];
    const ranked = rankResults(servers, 'test');
    expect(ranked[0]?.name).toBe('new-server');
  });

  it('handles missing lastUpdated gracefully', () => {
    const servers = [
      makeServer({ name: 'no-date' }),
      makeServer({ name: 'has-date', lastUpdated: new Date() }),
    ];
    // Should not throw
    const ranked = rankResults(servers, 'test');
    expect(ranked).toHaveLength(2);
  });

  it('produces stable ordering for identical scores', () => {
    const servers = Array.from({ length: 10 }, (_, i) =>
      makeServer({ name: `server-${String(i)}` }),
    );
    const ranked1 = rankResults(servers, 'test');
    const ranked2 = rankResults(servers, 'test');
    expect(ranked1.map((s) => s.name)).toEqual(ranked2.map((s) => s.name));
  });

  it('returns empty array for empty input', () => {
    expect(rankResults([], 'test')).toEqual([]);
  });

  it('does not mutate original array', () => {
    const servers = [
      makeServer({ name: 'b' }),
      makeServer({ name: 'a' }),
    ];
    const original = [...servers];
    rankResults(servers, 'test');
    expect(servers.map((s) => s.name)).toEqual(original.map((s) => s.name));
  });
});
