import {
  describe,
  it,
  expect,
  vi
} from 'vitest';
import { HttpClient, HttpParams } from '@angular/common/http';
import { Injector, runInInjectionContext } from '@angular/core';
import { of, throwError } from 'rxjs';
import { firstValueFrom } from 'rxjs';
import { ServerDirectoryApiService } from './server-directory-api.service';
import { ServerEndpointStateService } from '../../application/services/server-endpoint-state.service';

interface HarnessOptions {
  getResult?: unknown;
  getError?: unknown;
}

function createHarness(options: HarnessOptions = {}) {
  const get = vi.fn((..._args: unknown[]) =>
    options.getError ? throwError(() => options.getError) : of(options.getResult ?? { servers: [], total: 0 })
  );
  const http = { get } as unknown as HttpClient;
  const endpointState = {
    activeServer: () => ({ id: 'ep-1', name: 'Local', url: 'https://local.test', status: 'online' }),
    activeServers: () => [],
    servers: () => [],
    resolveCanonicalEndpoint: (endpoint: unknown) => endpoint ?? null,
    findServerByUrl: () => null,
    sanitiseUrl: (value: string) => value
  } as unknown as ServerEndpointStateService;
  const injector = Injector.create({
    providers: [
      ServerDirectoryApiService,
      { provide: HttpClient, useValue: http },
      { provide: ServerEndpointStateService, useValue: endpointState }
    ]
  });
  const service = runInInjectionContext(injector, () => injector.get(ServerDirectoryApiService));

  return { service, get };
}

describe('ServerDirectoryApiService discovery endpoints', () => {
  it('requests the featured endpoint and normalizes the response', async () => {
    const { service, get } = createHarness({
      getResult: { servers: [{ id: 's1', name: 'Alpha', currentUsers: 12 }], total: 1 }
    });
    const result = await firstValueFrom(service.getFeaturedServers());

    expect(get).toHaveBeenCalledWith('https://local.test/api/servers/featured', {});
    expect(result).toHaveLength(1);
    expect(result[0].id).toBe('s1');
    expect(result[0].userCount).toBe(12);
  });

  it('passes the limit as a query param for featured servers', async () => {
    const { service, get } = createHarness();

    await firstValueFrom(service.getFeaturedServers(5));

    const [url, options] = get.mock.calls[0];

    expect(url).toBe('https://local.test/api/servers/featured');
    expect((options as { params: HttpParams }).params.get('limit')).toBe('5');
  });

  it('requests the trending endpoint', async () => {
    const { service, get } = createHarness({ getResult: { servers: [], total: 0 } });

    await firstValueFrom(service.getTrendingServers());

    expect(get).toHaveBeenCalledWith('https://local.test/api/servers/trending', {});
  });

  it('returns an empty array when the discovery request fails', async () => {
    const { service } = createHarness({ getError: new Error('network') });
    const result = await firstValueFrom(service.getFeaturedServers());

    expect(result).toEqual([]);
  });
});
