import 'dart:async';
import 'dart:io';

void main() async {
  final projectRootPath = await Process.run(
    'git',
    ['rev-parse', '--show-toplevel'],
  ).then((result) => result.stdout.toString().trim());

  final backendPath = '$projectRootPath/backend';
  // Start the server
  print('Starting Dart Frog server...');
  final build = await Process.start(
    'dart_frog',
    ['build'],
    workingDirectory: backendPath,
    mode: ProcessStartMode.inheritStdio,
  );

  List<String> serverLogs = [];
  final server = await Process.start('dart', ['build/bin/server.dart'], workingDirectory: backendPath);
  server.stdout.transform(const SystemEncoding().decoder).listen((line) => serverLogs.add(line));
  server.stderr.transform(const SystemEncoding().decoder).listen((line) => serverLogs.add(line));

  // Wait for server to be ready
  print('Waiting for server to be ready...');
  await _waitForServer();

  print('Running tests...');
  try {
    // Run the tests
    final testResult = await Process.run('dart', ['test', '$backendPath/test_e2e/tests/']);
    stdout.write(testResult.stdout);
    stderr.write(testResult.stderr);

    // Kill the server regardless of test result
    server.kill();

    if (testResult.exitCode != 0) {
      final sub = serverLogs.length > 10 ? serverLogs.length - 10 : 0;
      stdout.write("Server logs:\n${serverLogs.sublist(sub).join('\n')}");
    }

    // Exit with the same code as the test process
    exit(testResult.exitCode);
  } catch (e) {
    print('Error running tests: $e');
    build.kill();
    server.kill();

    exit(1);
  }
}

Future<void> _waitForServer() async {
  final client = HttpClient();
  const maxAttempts = 30; // 30 seconds timeout
  var attempts = 0;

  while (attempts < maxAttempts) {
    try {
      final request =
          await client.getUrl(Uri.parse('http://localhost:8080/health')).timeout(const Duration(seconds: 1));
      final response = await request.close();
      await response.drain<void>();
      if (response.statusCode == 200) {
        print('Server is ready!');
        return;
      }
    } catch (e) {
      attempts++;
      await Future.delayed(const Duration(seconds: 1));
    }
  }
  throw Exception('Server failed to start after $maxAttempts seconds');
}