{{ header }}import { spawn } from 'child_process';
import { resolve } from 'path';

let serverProcess: any;

// HTTP client wrapper for making requests to mock server
const createApp = (baseUrl: string) => ({
  async request(path: string, init?: RequestInit): Promise<Response> {
    const url = new URL(path, baseUrl);
    return fetch(url.toString(), init);
  },
});

export async function setup() {
  // Mock server binary must be pre-built (e.g. by CI or `cargo build --manifest-path e2e/rust/Cargo.toml --bin mock-server --release`)
  serverProcess = spawn(
    resolve(__dirname, '../rust/target/release/mock-server'),
    [resolve(__dirname, '../../fixtures')],
    { stdio: ['pipe', 'pipe', 'inherit'] }
  );

  const { url, servers } = await new Promise<{ url: string; servers: Record<string, string> }>((resolve, reject) => {
    let collectedUrl = '';
    let collectedServers: Record<string, string> = {};
    let buffer = '';
    let settled = false;

    const finish = (result: { url: string; servers: Record<string, string> }) => {
      if (settled) return;
      settled = true;
      clearTimeout(startupTimeout);
      serverProcess.stdout.off('data', onData);
      resolve(result);
    };

    const onData = (data: any) => {
      buffer += data.toString();
      const lines = buffer.split('\n');
      buffer = lines.pop() ?? '';
      for (const line of lines) {
        const trimmed = line.trim();
        const urlMatch = trimmed.match(/^MOCK_SERVER_URL=(.*)/);
        if (urlMatch) {
          collectedUrl = urlMatch[1].trim();
        }
        const serversMatch = trimmed.match(/^MOCK_SERVERS=(.*)/);
        if (serversMatch) {
          try { collectedServers = JSON.parse(serversMatch[1].trim()); } catch { /* ignore */ }
          if (collectedUrl) finish({ url: collectedUrl, servers: collectedServers });
        } else if (collectedUrl && trimmed && !trimmed.startsWith('MOCK_SERVER')) {
          finish({ url: collectedUrl, servers: collectedServers });
        }
      }
    };

    const startupTimeout = setTimeout(() => {
      settled = true;
      serverProcess.stdout.off('data', onData);
      reject(new Error('Mock server startup timeout'));
    }, 30000);

    serverProcess.stdout.on('data', onData);
  });

  process.env.MOCK_SERVER_URL = url;
  for (const [fixtureId, fixtureUrl] of Object.entries(servers)) {
    process.env[`MOCK_SERVER_${fixtureId.toUpperCase()}`] = fixtureUrl;
  }
  process.env.MOCK_SERVERS = JSON.stringify(servers);

  // Make app available globally to all tests
  (globalThis as any).app = createApp(url);
}

export async function teardown() {
  if (!serverProcess) return;

  const child = serverProcess;
  serverProcess = undefined;

  await new Promise<void>((resolve) => {
    if (child.exitCode !== null || child.signalCode !== null) {
      resolve();
      return;
    }

    const timeout = setTimeout(() => {
      child.kill('SIGKILL');
      resolve();
    }, 5000);

    child.once('close', () => {
      clearTimeout(timeout);
      resolve();
    });

    child.stdin.end();
    child.kill('SIGTERM');
  });
}
