// Copyright 2014 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:developer';
import 'dart:io';
import 'dart:isolate';

import 'package:async/async.dart';
import 'package:coverage/coverage.dart';
import 'package:flutter_tools/src/context_runner.dart';
import 'package:path/path.dart' as path;
import 'package:pedantic/pedantic.dart';
import 'package:stream_channel/isolate_channel.dart';
import 'package:stream_channel/stream_channel.dart';
import 'package:test_core/src/runner/hack_register_platform.dart' as hack; // ignore: implementation_imports
import 'package:test_core/src/executable.dart' as test; // ignore: implementation_imports
import 'package:vm_service_client/vm_service_client.dart'; // ignore: deprecated_member_use
import 'package:test_api/src/backend/runtime.dart'; // ignore: implementation_imports
import 'package:test_api/src/backend/suite_platform.dart'; // ignore: implementation_imports
import 'package:test_core/src/runner/platform.dart'; // ignore: implementation_imports
import 'package:test_core/src/runner/runner_suite.dart'; // ignore: implementation_imports
import 'package:test_core/src/runner/suite.dart'; // ignore: implementation_imports
import 'package:test_core/src/runner/plugin/platform_helpers.dart'; // ignore: implementation_imports
import 'package:test_core/src/runner/environment.dart'; // ignore: implementation_imports
import 'package:flutter_tools/src/project.dart';
import 'package:flutter_tools/src/test/coverage_collector.dart';

/// Generates an lcov report for the flutter tool unit tests.
///
/// Example invocation:
///
///     dart tool/tool_coverage.dart
Future<void> main(List<String> arguments) async {
  return runInContext(() async {
    final VMPlatform vmPlatform = VMPlatform();
    hack.registerPlatformPlugin(
      <Runtime>[Runtime.vm],
      () => vmPlatform,
    );
    if (arguments.isEmpty) {
      arguments = <String>[
        path.join('test', 'general.shard'),
        path.join('test', 'commands.shard', 'hermetic'),
      ];
    }
    await test.main(<String>[
      '--no-color',
      '-r', 'compact',
      '-j', '1',
      ...arguments
    ]);
    exit(exitCode);
  });
}

/// A platform that loads tests in isolates spawned within this Dart process.
class VMPlatform extends PlatformPlugin {
  final CoverageCollector coverageCollector = CoverageCollector(
    libraryPredicate: (String libraryName) => libraryName.contains(FlutterProject.current().manifest.appName),
  );
  final Map<String, Future<void>> _pending = <String, Future<void>>{};
  final String precompiledPath = path.join('.dart_tool', 'build', 'generated', 'flutter_tools');

  @override
  StreamChannel<void> loadChannel(String codePath, SuitePlatform platform) =>
      throw UnimplementedError();

  @override
  Future<RunnerSuite> load(
    String codePath,
    SuitePlatform platform,
    SuiteConfiguration suiteConfig,
    Object message,
  ) async {
    final ReceivePort receivePort = ReceivePort();
    Isolate isolate;
    try {
      isolate = await _spawnIsolate(codePath, receivePort.sendPort);
    } catch (error) {
      receivePort.close();
      rethrow;
    }
    final Completer<void> completer = Completer<void>();
    // When this is completed we remove it from the map of pending so we can
    // log the futures that get "stuck".
    unawaited(completer.future.whenComplete(() {
      _pending.remove(codePath);
    }));
    final ServiceProtocolInfo info = await Service.controlWebServer(enable: true);
    final StreamChannel<Object> channel = IsolateChannel<Object>.connectReceive(receivePort)
      .transformStream(StreamTransformer<Object, Object>.fromHandlers(
        handleDone: (EventSink<Object> sink) async {
          try {
            // this will throw if collection fails.
            await coverageCollector.collectCoverageIsolate(info.serverUri);
          } finally {
            isolate.kill(priority: Isolate.immediate);
            isolate = null;
            sink.close();
            completer.complete();
          }
        },
        handleError: (dynamic error, StackTrace stackTrace, EventSink<Object> sink) {
          isolate.kill(priority: Isolate.immediate);
          isolate = null;
          sink.close();
          completer.complete();
        },
      ));

    VMEnvironment environment;
    final RunnerSuiteController controller = deserializeSuite(
      codePath,
      platform,
      suiteConfig,
      environment,
      channel,
      message,
    );
    _pending[codePath] = completer.future;
    return await controller.suite;
  }

  /// Spawns an isolate and passes it [message].
  ///
  /// This isolate connects an [IsolateChannel] to [message] and sends the
  /// serialized tests over that channel.
  Future<Isolate> _spawnIsolate(String codePath, SendPort message) async {
    String testPath = path.absolute(path.join(precompiledPath, codePath) + '.vm_test.dart');
    testPath = testPath.substring(0, testPath.length - '.dart'.length) + '.vm.app.dill';
    return await Isolate.spawnUri(path.toUri(testPath), <String>[], message,
      packageConfig: path.toUri('.packages'),
      checked: true,
    );
  }

  @override
  Future<void> close() async {
    try {
      await Future.wait(_pending.values).timeout(const Duration(minutes: 1));
    } on TimeoutException {
      // TODO(jonahwilliams): resolve whether there are any specific tests that
      // get stuck or if it is a general infra issue with how we are collecting
      // coverage.
      // Log tests that are "Stuck" waiting for coverage.
      print('The following tests timed out waiting for coverage:');
      print(_pending.keys.join(', '));
    }
    final String packagePath = Directory.current.path;
    final Resolver resolver = Resolver(packagesPath: '.packages');
    final Formatter formatter = LcovFormatter(resolver, reportOn: <String>[
      'lib',
    ], basePath: packagePath);
    final String result = await coverageCollector.finalizeCoverage(
      formatter: formatter,
    );
    final String outputLcovPath = path.join('coverage', 'lcov.info');
    File(outputLcovPath)
      ..createSync(recursive: true)
      ..writeAsStringSync(result);
  }
}

class VMEnvironment implements Environment {
  VMEnvironment(this.observatoryUrl, this._isolate);

  @override
  final bool supportsDebugging = false;

  @override
  final Uri observatoryUrl;

  /// The VM service isolate object used to control this isolate.
  final VMIsolateRef _isolate;

  @override
  Uri get remoteDebuggerUrl => null;

  @override
  Stream<void> get onRestart => StreamController<dynamic>.broadcast().stream;

  @override
  CancelableOperation<void> displayPause() {
    final CancelableCompleter<dynamic> completer = CancelableCompleter<dynamic>(onCancel: () => _isolate.resume());

    completer.complete(_isolate.pause().then((dynamic _) => _isolate.onPauseOrResume
        .firstWhere((VMPauseEvent event) => event is VMResumeEvent)));

    return completer.operation;
  }
}
