// Copyright (c) 2016, 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.md file.

library testing.run_tests;

import 'dart:async' show Future;

import 'dart:io' show Directory, File, FileSystemEntity;

import 'dart:io' as io show exitCode;

import 'dart:isolate' show Isolate;

import 'error_handling.dart' show withErrorHandling;

import 'test_root.dart' show TestRoot;

import 'zone_helper.dart' show runGuarded;

import 'log.dart' show enableVerboseOutput, isVerbose, StdoutLogger;

import 'run.dart' show SuiteRunner, runProgram;

class CommandLine {
  final Set<String> options;
  final List<String> arguments;

  CommandLine(this.options, this.arguments);

  bool get verbose => options.contains("--verbose") || options.contains("-v");

  Set<String> get skip => commaSeparated("--skip=");

  Set<String> commaSeparated(String prefix) {
    return Set<String>.from(options.expand((String s) {
      if (!s.startsWith(prefix)) return const [];
      s = s.substring(prefix.length);
      return s.split(",");
    }));
  }

  Map<String, String> get environment {
    Map<String, String> result = <String, String>{};
    for (String option in options) {
      if (option.startsWith("-D")) {
        int equalIndex = option.indexOf("=");
        if (equalIndex != -1) {
          String key = option.substring(2, equalIndex);
          String value = option.substring(equalIndex + 1);
          result[key] = value;
        }
      }
    }
    return result;
  }

  Set<String> get selectedSuites {
    return selectors.map((String selector) {
      int index = selector.indexOf("/");
      return index == -1 ? selector : selector.substring(0, index);
    }).toSet();
  }

  Iterable<String> get selectors => arguments;

  Future<Uri?> get configuration async {
    const String configPrefix = "--config=";
    List<String> configurationPaths = options
        .where((String option) => option.startsWith(configPrefix))
        .map((String option) => option.substring(configPrefix.length))
        .toList();
    if (configurationPaths.length > 1) {
      return fail("Only one --config option is supported");
    }
    String configurationPath;
    if (configurationPaths.length == 1) {
      configurationPath = configurationPaths.single;
      File file = File(configurationPath);
      if (await file.exists()) {
        // If [configurationPath] exists as a file, use the absolute URI. This
        // handles absolute paths on Windows.
        configurationPath = file.absolute.uri.toString();
      }
    } else {
      configurationPath = "testing.json";
      if (!await File(configurationPath).exists()) {
        Directory test = Directory("test");
        if (await test.exists()) {
          List<FileSystemEntity> candidates = await test
              .list(recursive: true, followLinks: false)
              .where((FileSystemEntity entity) {
            return entity is File && entity.uri.path.endsWith("/testing.json");
          }).toList();
          switch (candidates.length) {
            case 0:
              return fail("Couldn't locate: '$configurationPath'.");

            case 1:
              configurationPath = candidates.single.path;
              break;

            default:
              return fail(
                  "Usage: run_tests.dart [$configPrefix=configuration_file]\n"
                  "Where configuration_file is one of:\n  "
                  "${candidates.map((file) => file.path).join('\n  ')}");
          }
        }
      }
    }
    const StdoutLogger()
        .logMessage("Reading configuration file '$configurationPath'.");
    Uri? configuration =
        await Isolate.resolvePackageUri(Uri.base.resolve(configurationPath));
    if (configuration == null || !await File.fromUri(configuration).exists()) {
      return fail("Couldn't locate: '$configurationPath'.");
    }
    return configuration;
  }

  static CommandLine parse(List<String> arguments) {
    int index = arguments.indexOf("--");
    Set<String> options;
    if (index != -1) {
      options = Set<String>.from(arguments.getRange(0, index));
      arguments = arguments.sublist(index + 1);
    } else {
      options = arguments.where((argument) => argument.startsWith("-")).toSet();
      arguments =
          arguments.where((argument) => !argument.startsWith("-")).toList();
    }
    return CommandLine(options, arguments);
  }
}

fail(String message) {
  print(message);
  io.exitCode = 1;
  return null;
}

main(List<String> arguments) => withErrorHandling(() async {
      CommandLine cl = CommandLine.parse(arguments);
      if (cl.verbose) {
        enableVerboseOutput();
      }
      Map<String, String> environment = cl.environment;
      Uri? configuration = await cl.configuration;
      if (configuration == null) return;
      if (!isVerbose) {
        print("Use --verbose to display more details.");
      }
      TestRoot root = await TestRoot.fromUri(configuration);
      SuiteRunner runner = SuiteRunner(
          root.suites, environment, cl.selectors, cl.selectedSuites, cl.skip);
      String? program = await runner.generateDartProgram();
      bool hasAnalyzerSuites = await runner.analyze(root.packages);
      Stopwatch sw = Stopwatch()..start();
      if (program == null) {
        if (!hasAnalyzerSuites) {
          fail("No tests configured.");
        }
      } else {
        await runProgram(program, root.packages);
      }
      print("Running tests took: ${sw.elapsed}.");
    });

Future<void> runTests(Map<String, Function> tests) =>
    withErrorHandling<void>(() async {
      int completed = 0;
      for (String name in tests.keys) {
        const StdoutLogger()
            .logTestStart(completed, 0, tests.length, null, null);
        StringBuffer sb = StringBuffer();
        try {
          await runGuarded(() {
            print("Running test $name");
            return tests[name]!();
          }, printLineOnStdout: sb.writeln);
          const StdoutLogger().logMessage(sb);
        } catch (e) {
          print(sb);
          rethrow;
        }
        const StdoutLogger()
            .logTestComplete(++completed, 0, tests.length, null, null);
      }
    });
