// Copyright (c) 2019, the Dart project authors.  Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.

// @dart = 2.9

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

import 'package:path/path.dart' as path;

main(List<String> args) async {
  if (args.length != 1) {
    print('Usage ${Platform.executable} ${Platform.script} <output-dir>');
    exit(1);
  }

  final sdkRoot =
      path.canonicalize(path.join(Platform.script.path, '../../..'));
  final flutterTestsDir = args.single;

  print('Using SDK root: $sdkRoot');
  final testFiles = <String>[];
  final failedOrTimedOut = <String>[];
  final filteredTests = <String>[];
  await for (final testFile in listTestFiles(sdkRoot, filteredTests)) {
    final duration = await run(sdkRoot, testFile);
    if (duration != null && duration.inSeconds < 5) {
      testFiles.add(testFile);
    } else {
      failedOrTimedOut.add(testFile);
    }
  }
  testFiles.sort();
  failedOrTimedOut.sort();
  filteredTests.sort();

  dumpTestList(testFiles, 'The following tests will be included:');
  dumpTestList(failedOrTimedOut,
      'The following tests will be excluded due to timeout or test failure:');
  dumpTestList(
      filteredTests,
      'The following tests were filtered due to using '
      'dart_api.h/async/DynamicLibrary.{process,executable}/...');

  final allFiles = <String>{};
  allFiles.add(path.join(sdkRoot, 'pkg/expect/lib/expect.dart'));
  for (final testFile in testFiles) {
    allFiles.add(testFile);
    await addImportedFilesTo(allFiles, testFile);
  }

  await generateCleanDir(flutterTestsDir);

  final dartTestsDirRelative = 'example/lib';
  final dartTestsDir = path.join(flutterTestsDir, dartTestsDirRelative);
  await generateDartTests(dartTestsDir, allFiles, testFiles);

  final ccDirRelative = 'ios/Classes';
  final ccDir = path.join(flutterTestsDir, ccDirRelative);
  await generateCLibs(sdkRoot, ccDir, allFiles, testFiles);

  print('''

Files generated in:
  * $dartTestsDir
  * $ccDir

Generate flutter test application with:
  flutter create --platforms=android,ios --template=plugin <ffi_test_app_name>

Please copy generated files into FFI flutter test application:
  cd <ffi_test_app_dir> && cp -r $flutterTestsDir ./

After copying modify the test application:
  * Modify example/pubspec.yaml to depend on package:ffi.
  * Modify example/lib/main.dart to invoke all.dart while rendering.
  * Open example/ios/Runner.xcworkspace in Xcode.
    * Add the cpp files to Pods/Development Pods/<deep nesting>/ios/Classes
      to ensure they are statically linked to the app.
''');
}

void dumpTestList(List<String> testFiles, String message) {
  if (testFiles.isEmpty) return;

  print(message);
  for (final testFile in testFiles) {
    print('  ${path.basename(testFile)}');
  }
}

final importRegExp = RegExp(r'''^import.*['"](.+)['"].*;''');

Future addImportedFilesTo(Set<String> allFiles, String testFile) async {
  final content = await File(testFile).readAsString();
  for (final line in content.split('\n')) {
    final match = importRegExp.matchAsPrefix(line);
    if (match != null) {
      final filename = match.group(1);
      if (!filename.contains('dart:') &&
          !filename.contains('package:expect') &&
          !filename.contains('package:ffi')) {
        final importedFile = Uri.file(testFile).resolve(filename).toFilePath();
        if (allFiles.add(importedFile)) {
          addImportedFilesTo(allFiles, importedFile);
        }
      }
    }
  }
}

Future generateCLibs(String sdkRoot, String destDir, Set<String> allFiles,
    List<String> testFiles) async {
  final dir = await generateCleanDir(destDir);

  String destinationFile;

  final lib1 =
      path.join(sdkRoot, 'runtime/bin/ffi_test/ffi_test_dynamic_library.cc');
  destinationFile =
      path.join(dir.path, path.basename(lib1)).replaceAll('.cc', '.cpp');
  File(destinationFile).writeAsStringSync(File(lib1).readAsStringSync());

  final lib2 = path.join(sdkRoot, 'runtime/bin/ffi_test/ffi_test_functions.cc');
  destinationFile =
      path.join(dir.path, path.basename(lib2)).replaceAll('.cc', '.cpp');
  File(destinationFile).writeAsStringSync(File(lib2).readAsStringSync());

  final lib3 = path.join(
      sdkRoot, 'runtime/bin/ffi_test/ffi_test_functions_generated.cc');
  destinationFile =
      path.join(dir.path, path.basename(lib3)).replaceAll('.cc', '.cpp');
  File(destinationFile).writeAsStringSync(File(lib3).readAsStringSync());
}

String cleanDart(String content) {
  return content.replaceAll('package:expect/expect.dart', 'expect.dart');
}

Future generateDartTests(
    String destDir, Set<String> allFiles, List<String> testFiles) async {
  final dir = await generateCleanDir(destDir);

  final sink = File(path.join(dir.path, 'all.dart')).openWrite();
  sink.writeln('import "dart:async";');
  sink.writeln('');
  for (int i = 0; i < testFiles.length; ++i) {
    sink.writeln('import "${path.basename(testFiles[i])}" as main$i;');
  }
  sink.writeln('');
  sink.writeln('Future invoke(dynamic fun) async {');
  sink.writeln('  if (fun is void Function() || fun is Future Function()) {');
  sink.writeln('    return await fun();');
  sink.writeln('  } else {');
  sink.writeln('    return await fun(<String>[]);');
  sink.writeln('  }');
  sink.writeln('}');
  sink.writeln('');
  sink.writeln('dynamic main() async {');
  for (int i = 0; i < testFiles.length; ++i) {
    sink.writeln('  await invoke(main$i.main);');
  }
  sink.writeln('}');
  await sink.close();

  for (final file in allFiles) {
    File(path.join(dir.path, path.basename(file)))
        .writeAsStringSync(cleanDart(File(file).readAsStringSync()));
  }

  File(path.join(dir.path, 'dylib_utils.dart')).writeAsStringSync('''
import 'dart:ffi' as ffi;
import 'dart:io' show Platform;

ffi.DynamicLibrary dlopenPlatformSpecific(String name, {String path}) {
  return Platform.isAndroid
      ? ffi.DynamicLibrary.open('libffi_tests.so')
      : ffi.DynamicLibrary.process();
}
''');
}

Stream<String> listTestFiles(
    String sdkRoot, List<String> filteredTests) async* {
  await for (final file
      in Directory(path.join(sdkRoot, 'tests/ffi_2')).list()) {
    if (file is File && file.path.endsWith('_test.dart')) {
      // These tests are VM specific and cannot necessarily be run on Flutter.
      if (path.basename(file.path).startsWith('vmspecific_')) {
        filteredTests.add(file.path);
        continue;
      }
      // These tests use special features which are hard to test on Flutter.
      final contents = file.readAsStringSync();
      if (contents.contains(RegExp('//# .* compile-time error')) ||
          contents.contains('DynamicLibrary.process') ||
          contents.contains('DynamicLibrary.executable')) {
        filteredTests.add(file.path);
        continue;
      }
      yield file.path;
    }
  }
}

Future<Duration> run(String sdkRoot, String testFile) async {
  final env = Map<String, String>.from(Platform.environment);
  env['LD_LIBRARY_PATH'] = path.join(sdkRoot, 'out/ReleaseX64');
  final sw = Stopwatch()..start();
  final Process process = await Process.start(
      Platform.executable, <String>[testFile],
      environment: env);
  final timer = Timer(const Duration(seconds: 3), () => process.kill());
  process.stdout.listen((_) {});
  process.stderr.listen((_) {});
  if (await process.exitCode != 0) return null;
  timer.cancel();
  return sw.elapsed;
}

Future<Directory> generateCleanDir(String dirname) async {
  final directory = Directory(dirname);
  if (await directory.exists()) {
    await directory.delete(recursive: true);
  }
  await directory.create(recursive: true);
  return directory;
}
