// 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 '../base/common.dart';
import '../base/io.dart';
import '../base/os.dart';
import '../base/process.dart';
import '../base/version.dart';
import '../cache.dart';
import '../dart/pub.dart';
import '../globals.dart' as globals;
import '../runner/flutter_command.dart';
import '../version.dart';

class VersionCommand extends FlutterCommand {
  VersionCommand() : super() {
    argParser.addFlag('force',
      abbr: 'f',
      help: 'Force switch to older Flutter versions that do not include a version command',
    );
    // Don't use usesPubOption here. That will cause the version command to
    // require a pubspec.yaml file, which it doesn't need.
    argParser.addFlag('pub',
      defaultsTo: true,
      hide: true,
      help: 'Whether to run "flutter pub get" after switching versions.',
    );
  }

  @override
  final String name = 'version';

  @override
  final String description = 'List or switch flutter versions.';

  // The first version of Flutter which includes the flutter version command. Switching to older
  // versions will require the user to manually upgrade.
  Version minSupportedVersion = Version.parse('1.2.1');

  Future<List<String>> getTags() async {
    RunResult runResult;
    try {
      runResult = await processUtils.run(
        <String>['git', 'tag', '-l', 'v*', '--sort=-creatordate'],
        throwOnError: true,
        workingDirectory: Cache.flutterRoot,
      );
    } on ProcessException catch (error) {
      throwToolExit(
        'Unable to get the tags. '
        'This might be due to git not being installed or an internal error'
        '\nError: $error.'
      );
    }
    return runResult.toString().split('\n');
  }

  @override
  Future<FlutterCommandResult> runCommand() async {
    final List<String> tags = await getTags();
    if (argResults.rest.isEmpty) {
      tags.forEach(globals.printStatus);
      return FlutterCommandResult.success();
    }

    globals.printStatus(
      '╔══════════════════════════════════════════════════════════════════════════════╗\n'
      '║ Warning: "flutter version" will leave the SDK in a detached HEAD state.      ║\n'
      '║ If you are using the command to return to a previously installed SDK version ║\n'
      '║ consider using the "flutter downgrade" command instead.                      ║\n'
      '╚══════════════════════════════════════════════════════════════════════════════╝\n',
      emphasis: true,
    );
    if (globals.stdio.stdinHasTerminal) {
      globals.terminal.usesTerminalUi = true;
      final String result = await globals.terminal.promptForCharInput(
        <String>['y', 'n'],
        logger: globals.logger,
        prompt: 'Are you sure you want to proceed?'
      );
      if (result == 'n') {
        return FlutterCommandResult.success();
      }
    }

    final String version = argResults.rest[0].replaceFirst('v', '');
    if (!tags.contains('v$version')) {
      globals.printError('There is no version: $version');
    }

    // check min supported version
    final Version targetVersion = Version.parse(version);
    if (targetVersion == null) {
      throwToolExit('Failed to parse version "$version"');
    }

    bool withForce = false;
    if (targetVersion < minSupportedVersion) {
      if (!boolArg('force')) {
        globals.printError(
          'Version command is not supported in $targetVersion and it is supported since version $minSupportedVersion '
          'which means if you switch to version $minSupportedVersion then you can not use version command. '
          'If you really want to switch to version $targetVersion, please use `--force` flag: `flutter version --force $targetVersion`.'
        );
        return const FlutterCommandResult(ExitStatus.success);
      }
      withForce = true;
    }

    try {
      await processUtils.run(
        <String>['git', 'checkout', 'v$version'],
        throwOnError: true,
        workingDirectory: Cache.flutterRoot,
      );
    } catch (e) {
      throwToolExit('Unable to checkout version branch for version $version.');
    }

    final FlutterVersion flutterVersion = FlutterVersion();

    globals.printStatus('Switching Flutter to version ${flutterVersion.frameworkVersion}${withForce ? ' with force' : ''}');

    // Check for and download any engine and pkg/ updates.
    // We run the 'flutter' shell script re-entrantly here
    // so that it will download the updated Dart and so forth
    // if necessary.
    globals.printStatus('');
    globals.printStatus('Downloading engine...');
    int code = await processUtils.stream(<String>[
      globals.fs.path.join('bin', 'flutter'),
      '--no-color',
      'precache',
    ], workingDirectory: Cache.flutterRoot, allowReentrantFlutter: true);

    if (code != 0) {
      throwToolExit(null, exitCode: code);
    }

    globals.printStatus('');
    globals.printStatus(flutterVersion.toString());

    final String projectRoot = findProjectRoot();
    if (projectRoot != null && boolArg('pub')) {
      globals.printStatus('');
      await pub.get(
        context: PubContext.pubUpgrade,
        directory: projectRoot,
        upgrade: true,
        checkLastModified: false,
      );
    }

    // Run a doctor check in case system requirements have changed.
    globals.printStatus('');
    globals.printStatus('Running flutter doctor...');
    code = await processUtils.stream(
      <String>[
        globals.fs.path.join('bin', 'flutter'),
        'doctor',
      ],
      workingDirectory: Cache.flutterRoot,
      allowReentrantFlutter: true,
    );

    if (code != 0) {
      throwToolExit(null, exitCode: code);
    }

    return FlutterCommandResult.success();
  }
}
