// Copyright (c) 2020, 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.

/// A trivial embedding of the pub command. Used from tests.
import 'dart:convert';
import 'dart:io';

import 'package:args/args.dart';
import 'package:args/command_runner.dart';
import 'package:pub/pub.dart';
import 'package:pub/src/command.dart';
import 'package:pub/src/exit_codes.dart' as exit_codes;
import 'package:pub/src/log.dart' as log;
import 'package:pub/src/utils.dart';
import 'package:usage/usage.dart';

final Analytics loggingAnalytics = _LoggingAnalytics();

// A command for explicitly throwing an exception, to test the handling of
// unexpected eceptions.
class ThrowingCommand extends PubCommand {
  @override
  String get name => 'fail';

  @override
  String get description => 'Throws an exception';

  bool get hide => true;

  @override
  Future<int> runProtected() async {
    throw StateError('Pub has crashed');
  }
}

// A command for testing the ensurePubspecResolved functionality
class EnsurePubspecResolvedCommand extends PubCommand {
  @override
  String get name => 'ensure-pubspec-resolved';

  @override
  String get description => 'Resolves pubspec.yaml if needed';

  @override
  bool get hidden => true;

  @override
  Future<int> runProtected() async {
    await ensurePubspecResolved('.');
    return 0;
  }
}

class RunCommand extends Command<int> {
  @override
  String get name => 'run';

  @override
  String get description => 'runs a dart app';

  @override
  Future<int> run() async {
    final executable = await getExecutableForCommand(argResults!.rest.first);
    final packageConfig = executable.packageConfig;
    final process = await Process.start(
      Platform.executable,
      [
        if (packageConfig != null) '--packages=$packageConfig',
        executable.executable,
        ...argResults!.rest.skip(1)
      ],
      mode: ProcessStartMode.inheritStdio,
    );

    return await process.exitCode;
  }
}

class Runner extends CommandRunner<int> {
  late ArgResults _results;

  Runner() : super('pub_command_runner', 'Tests the embeddable pub command.') {
    final analytics = Platform.environment['_PUB_LOG_ANALYTICS'] == 'true'
        ? PubAnalytics(
            () => loggingAnalytics,
            dependencyKindCustomDimensionName: 'cd1',
          )
        : null;
    addCommand(
      pubCommand(
        analytics: analytics,
        isVerbose: () => _results.flag('verbose'),
      )
        ..addSubcommand(ThrowingCommand())
        ..addSubcommand(EnsurePubspecResolvedCommand()),
    );
    addCommand(RunCommand());
    argParser.addFlag('verbose');
  }

  @override
  Future<int> run(Iterable<String> args) async {
    try {
      _results = super.parse(args);
      if (_results.flag('verbose')) {
        log.verbosity = log.Verbosity.all;
      }
      return await runCommand(_results);
    } on UsageException catch (error) {
      log.exception(error);
      return exit_codes.USAGE;
    }
  }

  @override
  Future<int> runCommand(ArgResults topLevelResults) async {
    return await super.runCommand(topLevelResults) ?? 0;
  }
}

Future<void> main(List<String> arguments) async {
  exitCode = await Runner().run(arguments);
}

class _LoggingAnalytics extends AnalyticsMock {
  _LoggingAnalytics() {
    onSend.listen((event) {
      stderr.writeln('[analytics]${json.encode(event)}');
    });
  }

  @override
  bool get firstRun => false;

  @override
  Future sendScreenView(String viewName, {Map<String, String>? parameters}) {
    parameters ??= <String, String>{};
    parameters['viewName'] = viewName;
    return _log('screenView', parameters);
  }

  @override
  Future sendEvent(
    String category,
    String action, {
    String? label,
    int? value,
    Map<String, String>? parameters,
  }) {
    parameters ??= <String, String>{};
    return _log(
      'event',
      {'category': category, 'action': action, 'label': label, 'value': value}
        ..addAll(parameters),
    );
  }

  @override
  Future sendSocial(String network, String action, String target) =>
      _log('social', {'network': network, 'action': action, 'target': target});

  @override
  Future sendTiming(
    String variableName,
    int time, {
    String? category,
    String? label,
  }) {
    return _log('timing', {
      'variableName': variableName,
      'time': time,
      'category': category,
      'label': label
    });
  }

  Future<void> _log(String hitType, Map message) async {
    final encoded = json.encode({'hitType': hitType, 'message': message});
    stderr.writeln('[analytics]: $encoded');
  }
}
