// 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.

/// This executable provides the ability to run the migration tool in process
/// on a single package.  It should be invoked with two command-line arguments:
/// a path to a configuration file and the name of a package to migrate.
///
/// The configuration file format is a JSON map, with the following keys:
/// - `sdk_root`: path to the SDK source code on the user's machine (this is the
///   directory that contains `pkg`, `third_party`, `tests`, etc.
/// - `output_root`: if present, path to the directory on the user's machine
///   where output HTML files should go.  A subdirectory will be created for
///   each package that is migrated.
/// - `external_packages`: a map (name => path) of additional non-SDK packages
///   that may need to be migrated.
/// - `port`: if present, the port where a server should be spawned serving HTML
///   pages.
library migration_runner;

import 'dart:convert';
import 'dart:io' as io;

import 'package:analysis_server/protocol/protocol.dart';
import 'package:analysis_server/protocol/protocol_constants.dart';
import 'package:analysis_server/protocol/protocol_generated.dart';
import 'package:analysis_server/src/analysis_server.dart';
import 'package:analysis_server/src/utilities/mocks.dart';
import 'package:analyzer/file_system/file_system.dart';
import 'package:analyzer/file_system/physical_file_system.dart';
import 'package:analyzer/instrumentation/instrumentation.dart';
import 'package:analyzer/src/dart/sdk/sdk.dart';
import 'package:analyzer/src/generated/sdk.dart';
import 'package:path/path.dart' as path;
import 'package:test/test.dart';

main(List<String> args) async {
  if (args.length != 2) {
    throw StateError(
        'Exactly two arguments are required: the path to a JSON configuration '
        'file, and the name of the package to migrate');
  }
  var testInfoJsonPath = args[0];
  var testInfoJson = json.decode(io.File(testInfoJsonPath).readAsStringSync());
  var packageName = args[1];
  var testInfo = TestInfo(testInfoJson);
  var packageRoot = testInfo.packageRoot(packageName);
  var outputRoot = testInfo.outputRoot;
  var port = testInfo.port;
  String outputDir =
      outputRoot == null ? null : path.join(outputRoot, packageName);
  print('Preparing to migrate');
  var migrationTest = MigrationTest();
  migrationTest.setUp();
  print('Migrating');
  await migrationTest.run(packageRoot, outputDir, port);
  if (port == null) {
    print('Done');
    io.exit(0);
  } else {
    print('Done.  Please point your browser to localhost:$port/\$filePath');
  }
}

class MigrationBase {
  ResourceProvider resourceProvider = PhysicalResourceProvider.INSTANCE;
  MockServerChannel serverChannel;
  AnalysisServer server;

  AnalysisServer createAnalysisServer() {
    //
    // Create server
    //
    AnalysisServerOptions options = new AnalysisServerOptions();
    String sdkPath = FolderBasedDartSdk.defaultSdkDirectory(
      PhysicalResourceProvider.INSTANCE,
    ).path;
    return new AnalysisServer(serverChannel, resourceProvider, options,
        new DartSdkManager(sdkPath, true), InstrumentationService.NULL_SERVICE);
  }

  void processNotification(Notification notification) {
    if (notification.event == SERVER_NOTIFICATION_ERROR) {
      fail('${notification.toJson()}');
    }
  }

  Future<Response> sendAnalysisSetAnalysisRoots(List<String> directories) {
    var request =
        AnalysisSetAnalysisRootsParams(directories, []).toRequest('0');
    return waitResponse(request);
  }

  Future<Response> sendEditDartfix(
      List<String> directories, String outputDir, int port) {
    var request = EditDartfixParams(directories,
            includedFixes: ['non-nullable'], outputDir: outputDir, port: port)
        .toRequest('1');
    return waitResponse(request);
  }

  void setUp() {
    serverChannel = new MockServerChannel();
    server = createAnalysisServer();
    server.pluginManager = new TestPluginManager();
    // listen for notifications
    Stream<Notification> notificationStream =
        serverChannel.notificationController.stream;
    notificationStream.listen((Notification notification) {
      processNotification(notification);
    });
  }

  void tearDown() {
    server.done();
    server = null;
    serverChannel = null;
  }

  /// Returns a [Future] that completes when the server's analysis is complete.
  Future waitForTasksFinished() {
    return server.onAnalysisComplete;
  }

  /// Completes with a successful [Response] for the given [request].
  Future<Response> waitResponse(Request request,
      {bool throwOnError = true}) async {
    return serverChannel.sendRequest(request, throwOnError: throwOnError);
  }
}

class MigrationTest extends MigrationBase {
  Future<void> run(String packageRoot, String outputDir, int port) async {
    List<String> packageRoots = [packageRoot];
    await sendAnalysisSetAnalysisRoots(packageRoots);
    await sendEditDartfix(packageRoots, outputDir, port);
  }
}

class TestInfo {
  static const Set<String> thirdPartyPackages = {
    'charcode',
    'collection',
    'logging',
    'meta',
    'pedantic',
    'typed_data'
  };

  static const Set<String> builtInPackages = {'meta', 'path'};

  final Map<String, Object> testInfoJson;

  TestInfo(this.testInfoJson);

  Map<String, String> get externalPackages =>
      ((testInfoJson['external_packages'] ?? {}) as Map).cast<String, String>();

  String get outputRoot => testInfoJson['output_root'];

  int get port => testInfoJson['port'];

  String get sdkRoot => testInfoJson['sdk_root'];

  String packageRoot(String packageName) {
    if (thirdPartyPackages.contains(packageName)) {
      return path.join(sdkRoot, 'third_party', 'pkg', packageName);
    } else if (builtInPackages.contains(packageName)) {
      return path.join(sdkRoot, 'pkg', packageName);
    } else if (externalPackages.containsKey(packageName)) {
      return externalPackages[packageName];
    } else {
      throw StateError('Unrecognized package $packageName');
    }
  }
}
