/**
 * Test server helper for integration tests
 * 
 * For integration tests, we test against the actual running server.
 * This helper provides utilities for making HTTP requests to the test server.
 * 
 * The server should be started separately (e.g., via docker-compose or test setup script)
 * and the base URL should be provided via TEST_SERVER_URL environment variable.
 */

export interface TestServerConfig {
  baseUrl?: string;
  apiKey?: string;
  jwtToken?: string;
}

let defaultConfig: TestServerConfig = {};

/**
 * Initialize test server configuration
 */
export function initTestServer(config: TestServerConfig = {}): void {
  defaultConfig = {
    baseUrl: process.env.TEST_SERVER_URL || 'http://localhost:3001',
    apiKey: process.env.TEST_API_KEY || 'test-key-ce67dabb0d4e27e3d72877c921b89cae',
    ...config,
  };
}

/**
 * Get the base URL for test requests
 */
export function getTestServerUrl(): string {
  return defaultConfig.baseUrl || process.env.TEST_SERVER_URL || 'http://localhost:3001';
}

/**
 * Get test API key
 */
export function getTestApiKey(): string {
  return defaultConfig.apiKey || process.env.TEST_API_KEY || 'test-key-ce67dabb0d4e27e3d72877c921b89cae';
}

/**
 * Make an authenticated request to the test server with retry on rate limit
 */
export async function authenticatedRequest(
  endpoint: string,
  options: RequestInit = {},
  retryOnRateLimit: boolean = true
): Promise<Response> {
  const baseUrl = getTestServerUrl();
  const apiKey = getTestApiKey();
  
  const headers = new Headers(options.headers);
  headers.set('x-api-key', apiKey);
  headers.set('Content-Type', 'application/json');
  
  const makeRequest = async (): Promise<Response> => {
    return fetch(`${baseUrl}${endpoint}`, {
      ...options,
      headers,
    });
  };
  
  let response = await makeRequest();
  
  // Retry once on rate limit if enabled
  if (retryOnRateLimit && response.status === 429) {
    const data = await response.json().catch(() => ({}));
    const retryAfter = (data as any)?.retry_after_ms || 1000;
    
    // Wait for the retry period (max 5 seconds for tests)
    await new Promise(resolve => setTimeout(resolve, Math.min(retryAfter, 5000)));
    
    // Retry once
    response = await makeRequest();
  }
  
  return response;
}

/**
 * Make a JWT-authenticated request to the test server
 */
export async function jwtAuthenticatedRequest(
  endpoint: string,
  token: string,
  options: RequestInit = {}
): Promise<Response> {
  const baseUrl = getTestServerUrl();
  
  const headers = new Headers(options.headers);
  headers.set('Authorization', `Bearer ${token}`);
  headers.set('Content-Type', 'application/json');
  
  return fetch(`${baseUrl}${endpoint}`, {
    ...options,
    headers,
  });
}

/**
 * Make an unauthenticated request to the test server
 */
export async function unauthenticatedRequest(
  endpoint: string,
  options: RequestInit = {}
): Promise<Response> {
  const baseUrl = getTestServerUrl();
  
  const headers = new Headers(options.headers);
  headers.set('Content-Type', 'application/json');
  
  return fetch(`${baseUrl}${endpoint}`, {
    ...options,
    headers,
  });
}

/**
 * Wait for server to be ready (health check)
 */
export async function waitForServer(maxWaitMs: number = 30000): Promise<boolean> {
  const baseUrl = getTestServerUrl();
  const startTime = Date.now();
  
  while (Date.now() - startTime < maxWaitMs) {
    try {
      const response = await fetch(`${baseUrl}/health`);
      if (response.ok) {
        return true;
      }
    } catch (error) {
      // Server not ready yet
    }
    await new Promise(resolve => setTimeout(resolve, 500));
  }
  
  return false;
}

/**
 * Poll GET /api/runs/:id until run reaches target status or a terminal status.
 */
export async function pollRunUntilStatus(
  runId: string,
  targetStatus: string,
  options: { maxWaitMs?: number; intervalMs?: number } = {}
): Promise<Record<string, unknown>> {
  const maxWaitMs = options.maxWaitMs ?? 90000;
  const intervalMs = options.intervalMs ?? 1000;
  const start = Date.now();
  let lastRun: Record<string, unknown> = {};

  while (Date.now() - start < maxWaitMs) {
    const response = await authenticatedRequest(`/api/runs/${runId}`);
    const data = await response.json();
    const run = (data.run ?? data) as Record<string, unknown>;
    lastRun = run;

    if (run.status === targetStatus) {
      return run;
    }

    const terminal = ['failed', 'completed', 'killed'];
    if (terminal.includes(String(run.status)) && run.status !== targetStatus) {
      return run;
    }

    await new Promise((resolve) => setTimeout(resolve, intervalMs));
  }

  throw new Error(
    `Run ${runId} did not reach status ${targetStatus} within ${maxWaitMs}ms (last: ${String(lastRun.status)})`
  );
}

