// Copyright 2013 The Flutter Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

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

import 'package:args/command_runner.dart';

import 'common.dart';
import 'pipeline.dart';
import 'steps/compile_tests_step.dart';
import 'steps/run_tests_step.dart';
import 'utils.dart';

/// Runs build and test steps.
///
/// This command is designed to be invoked by the LUCI build graph. However, it
/// is also usable locally.
///
/// Usage:
///
///     felt run name_of_build_step
class RunCommand extends Command<bool> with ArgUtils<bool> {
  RunCommand() {
    argParser.addFlag(
      'list',
      abbr: 'l',
      help: 'Lists all available build steps.',
    );
    argParser.addFlag(
      'require-skia-gold',
      help: 'Whether we require Skia Gold to be available or not. When this '
            'flag is true, the tests will fail if Skia Gold is not available.',
    );
    argParser.addFlag(
      'wasm',
      help: 'Whether the test we are running are compiled to webassembly.'
    );
  }

  @override
  String get name => 'run';

  bool get isWasm => boolArg('wasm');

  bool get isListSteps => boolArg('list');

  /// When running screenshot tests, require Skia Gold to be available and
  /// reachable.
  bool get requireSkiaGold => boolArg('require-skia-gold');

  @override
  String get description => 'Runs a build step.';

  /// Build steps to run, in order specified.
  List<String> get stepNames => argResults!.rest;

  @override
  FutureOr<bool> run() async {
    // All available build steps.
    final Map<String, PipelineStep> buildSteps = <String, PipelineStep>{
      'compile_tests': CompileTestsStep(),
      for (final String browserName in kAllBrowserNames)
        'run_tests_$browserName': RunTestsStep(
          browserName: browserName,
          isDebug: false,
          isWasm: isWasm,
          doUpdateScreenshotGoldens: false,
          requireSkiaGold: requireSkiaGold,
          overridePathToCanvasKit: null,
        ),
    };

    if (isListSteps) {
      buildSteps.keys.forEach(print);
      return true;
    }

    if (stepNames.isEmpty) {
      throw UsageException('No build steps specified.', argParser.usage);
    }

    final List<String> unrecognizedStepNames = <String>[];
    for (final String stepName in stepNames) {
      if (!buildSteps.containsKey(stepName)) {
        unrecognizedStepNames.add(stepName);
      }
    }
    if (unrecognizedStepNames.isNotEmpty) {
      io.stderr.writeln(
        'Unknown build steps specified: ${unrecognizedStepNames.join(', ')}',
      );
      return false;
    }

    final List<PipelineStep> steps = <PipelineStep>[];
    print('Running steps ${steps.join(', ')}');
    for (final String stepName in stepNames) {
      steps.add(buildSteps[stepName]!);
    }

    final Stopwatch stopwatch = Stopwatch()..start();
    final Pipeline pipeline = Pipeline(steps: steps);
    await pipeline.run();
    stopwatch.stop();
    print('Finished running steps in ${stopwatch.elapsedMilliseconds / 1000} seconds.');

    return true;
  }
}
