import { describe, it, expect, beforeAll, beforeEach, vi } from 'vitest';

const startDiscoveryMock = vi.fn();
const stopDiscoveryMock = vi.fn();

vi.mock('./discovery.js', () => ({
  startGatewayDiscovery: startDiscoveryMock,
}));

describe('GatewayServer discovery lifecycle', () => {
  let GatewayServer: typeof import('./server.js').GatewayServer;
  let server: import('./server.js').GatewayServer;

  const baseConfig = {
    port: 18910,
    host: '0.0.0.0',
    sessionManager: {
      getSession: () => ({ id: 's1', addMessage: () => {}, getHistory: () => [], clear: () => {}, setHistory: () => {}, replaceHistory: () => {} }),
      listSessions: () => [],
    } as unknown as import('./server.js').GatewayServerConfig['sessionManager'],
    modelClient: { chat: async () => ({ content: 'ok', usage: { inputTokens: 0, outputTokens: 0 }, stopReason: 'end_turn' }) },
    systemPrompt: 'test',
    toolRegistry: {
      list: () => [],
      get: () => undefined,
    } as unknown as import('./server.js').GatewayServerConfig['toolRegistry'],
    toolExecutor: { execute: async () => ({ success: true, output: '' }) } as unknown as import('./server.js').GatewayServerConfig['toolExecutor'],
    version: '0.1.0-test',
  } as const;

  beforeAll(async () => {
    ({ GatewayServer } = await import('./server.js'));
  });

  beforeEach(() => {
    vi.clearAllMocks();
    startDiscoveryMock.mockResolvedValue({
      stop: stopDiscoveryMock,
    });
    server = new GatewayServer({
      ...baseConfig,
      discovery: {
        enabled: true,
        serviceName: 'flynn-test',
        serviceType: '_flynn._tcp',
        txtRecord: { env: 'test' },
      },
    });
  });

  it('starts and stops discovery when enabled', async () => {
    const typedServer = server as unknown as { startDiscovery: (host: string, port: number) => Promise<void> };
    await typedServer.startDiscovery('0.0.0.0', 18910);
    await server.stop();

    expect(startDiscoveryMock).toHaveBeenCalledOnce();
    const [callConfig] = startDiscoveryMock.mock.calls[0] as [Record<string, unknown>];
    expect(callConfig.serviceName).toBe('flynn-test');
    expect(callConfig.serviceType).toBe('_flynn._tcp');
    expect(callConfig.port).toBe(18910);
    expect(callConfig.txtRecord).toMatchObject({
      env: 'test',
      version: '0.1.0-test',
    });
    expect(stopDiscoveryMock).toHaveBeenCalledOnce();
  });

  it('does not advertise when host is loopback', async () => {
    const typedServer = server as unknown as { startDiscovery: (host: string, port: number) => Promise<void> };
    await typedServer.startDiscovery('127.0.0.1', 18911);
    await server.stop();

    expect(startDiscoveryMock).not.toHaveBeenCalled();
    expect(stopDiscoveryMock).not.toHaveBeenCalled();
  });
});
