// 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';
import 'dart:typed_data';

import 'package:process/process.dart';

import 'base/common.dart';
import 'base/file_system.dart';
import 'base/logger.dart';
import 'base/terminal.dart';

/// The default name of the migrate working directory used to stage proposed changes.
const String kDefaultMigrateStagingDirectoryName = 'migrate_staging_dir';

/// Utility class that contains methods that wrap git and other shell commands.
class MigrateUtils {
  MigrateUtils({
    required Logger logger,
    required FileSystem fileSystem,
    required ProcessManager processManager,
  })  : _processManager = processManager,
        _logger = logger,
        _fileSystem = fileSystem;

  final Logger _logger;
  final FileSystem _fileSystem;
  final ProcessManager _processManager;

  Future<ProcessResult> _runCommand(List<String> command,
      {String? workingDirectory, bool runInShell = false}) {
    return _processManager.run(command,
        workingDirectory: workingDirectory, runInShell: runInShell);
  }

  /// Calls `git diff` on two files and returns the diff as a DiffResult.
  Future<DiffResult> diffFiles(File one, File two) async {
    if (one.existsSync() && !two.existsSync()) {
      return DiffResult(diffType: DiffType.deletion);
    }
    if (!one.existsSync() && two.existsSync()) {
      return DiffResult(diffType: DiffType.addition);
    }
    final List<String> cmdArgs = <String>[
      'git',
      'diff',
      '--no-index',
      one.absolute.path,
      two.absolute.path
    ];
    final ProcessResult result = await _runCommand(cmdArgs);

    // diff exits with 1 if diffs are found.
    checkForErrors(result,
        allowedExitCodes: <int>[0, 1],
        commandDescription: 'git ${cmdArgs.join(' ')}');
    return DiffResult(
        diffType: DiffType.command,
        diff: result.stdout as String,
        exitCode: result.exitCode);
  }

  /// Clones a copy of the flutter repo into the destination directory. Returns false if unsuccessful.
  Future<bool> cloneFlutter(String revision, String destination) async {
    // Use https url instead of ssh to avoid need to setup ssh on git.
    List<String> cmdArgs = <String>[
      'git',
      'clone',
      '--filter=blob:none',
      'https://github.com/flutter/flutter.git',
      destination
    ];
    ProcessResult result = await _runCommand(cmdArgs);
    checkForErrors(result, commandDescription: cmdArgs.join(' '));

    cmdArgs.clear();
    cmdArgs = <String>['git', 'reset', '--hard', revision];
    result = await _runCommand(cmdArgs, workingDirectory: destination);
    if (!checkForErrors(result,
        commandDescription: cmdArgs.join(' '), exit: false)) {
      return false;
    }
    return true;
  }

  /// Calls `flutter create` as a re-entrant command.
  Future<String> createFromTemplates(
    String flutterBinPath, {
    required String name,
    bool legacyNameParameter = false,
    required String androidLanguage,
    required String iosLanguage,
    required String outputDirectory,
    String? createVersion,
    List<String> platforms = const <String>[],
    int iterationsAllowed = 5,
  }) async {
    // Limit the number of iterations this command is allowed to attempt to prevent infinite looping.
    if (iterationsAllowed <= 0) {
      _logger.printError(
          'Unable to `flutter create` with the version of flutter at $flutterBinPath');
      return outputDirectory;
    }

    final List<String> cmdArgs = <String>['$flutterBinPath/flutter', 'create'];
    if (!legacyNameParameter) {
      cmdArgs.add('--project-name=$name');
    }
    cmdArgs.add('--android-language=$androidLanguage');
    cmdArgs.add('--ios-language=$iosLanguage');
    if (platforms.isNotEmpty) {
      String platformsArg = '--platforms=';
      for (int i = 0; i < platforms.length; i++) {
        if (i > 0) {
          platformsArg += ',';
        }
        platformsArg += platforms[i];
      }
      cmdArgs.add(platformsArg);
    }
    cmdArgs.add('--no-pub');
    if (legacyNameParameter) {
      cmdArgs.add(name);
    } else {
      cmdArgs.add(outputDirectory);
    }
    final ProcessResult result =
        await _runCommand(cmdArgs, workingDirectory: outputDirectory);
    final String error = result.stderr as String;

    // Catch errors due to parameters not existing.

    // Old versions of the tool does not include the platforms option.
    if (error.contains('Could not find an option named "platforms".')) {
      return createFromTemplates(
        flutterBinPath,
        name: name,
        legacyNameParameter: legacyNameParameter,
        androidLanguage: androidLanguage,
        iosLanguage: iosLanguage,
        outputDirectory: outputDirectory,
        iterationsAllowed: iterationsAllowed--,
      );
    }
    // Old versions of the tool does not include the project-name option.
    if ((result.stderr as String)
        .contains('Could not find an option named "project-name".')) {
      return createFromTemplates(
        flutterBinPath,
        name: name,
        legacyNameParameter: true,
        androidLanguage: androidLanguage,
        iosLanguage: iosLanguage,
        outputDirectory: outputDirectory,
        platforms: platforms,
        iterationsAllowed: iterationsAllowed--,
      );
    }
    if (error.contains('Multiple output directories specified.')) {
      if (error.contains('Try moving --platforms')) {
        return createFromTemplates(
          flutterBinPath,
          name: name,
          legacyNameParameter: legacyNameParameter,
          androidLanguage: androidLanguage,
          iosLanguage: iosLanguage,
          outputDirectory: outputDirectory,
          iterationsAllowed: iterationsAllowed--,
        );
      }
    }
    checkForErrors(result, commandDescription: cmdArgs.join(' '), silent: true);

    if (legacyNameParameter) {
      return _fileSystem.path.join(outputDirectory, name);
    }
    return outputDirectory;
  }

  /// Runs the git 3-way merge on three files and returns the results as a MergeResult.
  ///
  /// Passing the same path for base and current will perform a two-way fast forward merge.
  Future<MergeResult> gitMergeFile({
    required String base,
    required String current,
    required String target,
    required String localPath,
  }) async {
    final List<String> cmdArgs = <String>[
      'git',
      'merge-file',
      '-p',
      current,
      base,
      target
    ];
    final ProcessResult result = await _runCommand(cmdArgs);
    checkForErrors(result,
        allowedExitCodes: <int>[-1], commandDescription: cmdArgs.join(' '));
    return StringMergeResult(result, localPath);
  }

  /// Calls `git init` on the workingDirectory.
  Future<void> gitInit(String workingDirectory) async {
    final List<String> cmdArgs = <String>['git', 'init'];
    final ProcessResult result =
        await _runCommand(cmdArgs, workingDirectory: workingDirectory);
    checkForErrors(result, commandDescription: cmdArgs.join(' '));
  }

  /// Returns true if the workingDirectory git repo has any uncommited changes.
  Future<bool> hasUncommittedChanges(String workingDirectory,
      {String? migrateStagingDir}) async {
    final List<String> cmdArgs = <String>[
      'git',
      'ls-files',
      '--deleted',
      '--modified',
      '--others',
      '--exclude-standard',
      '--exclude=${migrateStagingDir ?? kDefaultMigrateStagingDirectoryName}'
    ];
    final ProcessResult result =
        await _runCommand(cmdArgs, workingDirectory: workingDirectory);
    checkForErrors(result,
        allowedExitCodes: <int>[-1], commandDescription: cmdArgs.join(' '));
    if ((result.stdout as String).isEmpty) {
      return false;
    }
    return true;
  }

  /// Returns true if the workingDirectory is a git repo.
  Future<bool> isGitRepo(String workingDirectory) async {
    final List<String> cmdArgs = <String>[
      'git',
      'rev-parse',
      '--is-inside-work-tree'
    ];
    final ProcessResult result =
        await _runCommand(cmdArgs, workingDirectory: workingDirectory);
    checkForErrors(result,
        allowedExitCodes: <int>[-1], commandDescription: cmdArgs.join(' '));
    if (result.exitCode == 0) {
      return true;
    }
    return false;
  }

  /// Returns true if the file at `filePath` is covered by the `.gitignore`
  Future<bool> isGitIgnored(String filePath, String workingDirectory) async {
    final List<String> cmdArgs = <String>['git', 'check-ignore', filePath];
    final ProcessResult result =
        await _runCommand(cmdArgs, workingDirectory: workingDirectory);
    checkForErrors(result,
        allowedExitCodes: <int>[0, 1, 128],
        commandDescription: cmdArgs.join(' '));
    return result.exitCode == 0;
  }

  /// Runs `flutter pub upgrade --major-revisions`.
  Future<void> flutterPubUpgrade(String workingDirectory) async {
    final List<String> cmdArgs = <String>[
      'flutter',
      'pub',
      'upgrade',
      '--major-versions'
    ];
    final ProcessResult result =
        await _runCommand(cmdArgs, workingDirectory: workingDirectory);
    checkForErrors(result, commandDescription: cmdArgs.join(' '));
  }

  /// Runs `./gradlew tasks` in the android directory of a flutter project.
  Future<void> gradlewTasks(String workingDirectory) async {
    final String baseCommand = isWindows ? 'gradlew.bat' : './gradlew';
    final List<String> cmdArgs = <String>[baseCommand, 'tasks'];
    final ProcessResult result = await _runCommand(cmdArgs,
        workingDirectory: workingDirectory, runInShell: isWindows);
    checkForErrors(result, commandDescription: cmdArgs.join(' '));
  }

  /// Verifies that the ProcessResult does not contain an error.
  ///
  /// If an error is detected, the error can be optionally logged or exit the tool.
  ///
  /// Passing -1 in allowedExitCodes means all exit codes are valid.
  bool checkForErrors(ProcessResult result,
      {List<int> allowedExitCodes = const <int>[0],
      String? commandDescription,
      bool exit = true,
      bool silent = false}) {
    if (allowedExitCodes.contains(result.exitCode) ||
        allowedExitCodes.contains(-1)) {
      return true;
    }
    if (!silent) {
      _logger.printError(
          'Command encountered an error with exit code ${result.exitCode}.');
      if (commandDescription != null) {
        _logger.printError('Command:');
        _logger.printError(commandDescription, indent: 2);
      }
      _logger.printError('Stdout:');
      _logger.printError(result.stdout as String, indent: 2);
      _logger.printError('Stderr:');
      _logger.printError(result.stderr as String, indent: 2);
    }
    if (exit) {
      throwToolExit(
          'Command failed with exit code ${result.exitCode}: ${result.stderr}\n${result.stdout}',
          exitCode: result.exitCode);
    }
    return false;
  }

  /// Returns true if the file does not contain any git conflit markers.
  bool conflictsResolved(String contents) {
    final bool hasMarker = contents.contains('>>>>>>>') ||
        contents.contains('=======') ||
        contents.contains('<<<<<<<');
    return !hasMarker;
  }
}

Future<bool> gitRepoExists(
    String projectDirectory, Logger logger, MigrateUtils migrateUtils) async {
  if (await migrateUtils.isGitRepo(projectDirectory)) {
    return true;
  }
  logger.printStatus(
      'Project is not a git repo. Please initialize a git repo and try again.');
  printCommand('git init', logger);
  return false;
}

Future<bool> hasUncommittedChanges(
    String projectDirectory, Logger logger, MigrateUtils migrateUtils) async {
  if (await migrateUtils.hasUncommittedChanges(projectDirectory)) {
    logger.printStatus(
        'There are uncommitted changes in your project. Please git commit, abandon, or stash your changes before trying again.');
    logger.printStatus('You may commit your changes using');
    printCommand('git add .', logger, newlineAfter: false);
    printCommand('git commit -m "<message>"', logger);
    return true;
  }
  return false;
}

void printCommand(String command, Logger logger, {bool newlineAfter = true}) {
  logger.printStatus(
    '\n\$ $command${newlineAfter ? '\n' : ''}',
    color: TerminalColor.grey,
    indent: 4,
    newline: false,
  );
}

/// Prints a command to logger with appropriate formatting.
void printCommandText(String command, Logger logger,
    {bool? standalone = true, bool newlineAfter = true}) {
  final String prefix = standalone == null
      ? ''
      : (standalone
          ? 'dart run <flutter_migrate_dir>${Platform.pathSeparator}bin${Platform.pathSeparator}flutter_migrate.dart '
          : 'flutter migrate ');
  printCommand('$prefix$command', logger, newlineAfter: newlineAfter);
}

/// Defines the classification of difference between files.
enum DiffType {
  command,
  addition,
  deletion,
  ignored,
  none,
}

/// Tracks the output of a git diff command or any special cases such as addition of a new
/// file or deletion of an existing file.
class DiffResult {
  DiffResult({
    required this.diffType,
    this.diff,
    this.exitCode,
  }) : assert(diffType == DiffType.command && exitCode != null ||
            diffType != DiffType.command && exitCode == null);

  /// The diff string output by git.
  final String? diff;

  final DiffType diffType;

  /// The exit code of the command. This is zero when no diffs are found.
  ///
  /// The exitCode is null when the diffType is not `command`.
  final int? exitCode;
}

/// Data class to hold the results of a merge.
abstract class MergeResult {
  /// Initializes a MergeResult based off of a ProcessResult.
  MergeResult(ProcessResult result, this.localPath)
      : hasConflict = result.exitCode != 0,
        exitCode = result.exitCode;

  /// Manually initializes a MergeResult with explicit values.
  MergeResult.explicit({
    required this.hasConflict,
    required this.exitCode,
    required this.localPath,
  });

  /// True when there is a merge conflict.
  bool hasConflict;

  /// The exitcode of the merge command.
  int exitCode;

  /// The local path relative to the project root of the file.
  String localPath;
}

/// The results of a string merge.
class StringMergeResult extends MergeResult {
  /// Initializes a BinaryMergeResult based off of a ProcessResult.
  StringMergeResult(super.result, super.localPath)
      : mergedString = result.stdout as String;

  /// Manually initializes a StringMergeResult with explicit values.
  StringMergeResult.explicit({
    required this.mergedString,
    required super.hasConflict,
    required super.exitCode,
    required super.localPath,
  }) : super.explicit();

  /// The final merged string.
  String mergedString;
}

/// The results of a binary merge.
class BinaryMergeResult extends MergeResult {
  /// Initializes a BinaryMergeResult based off of a ProcessResult.
  BinaryMergeResult(super.result, super.localPath)
      : mergedBytes = result.stdout as Uint8List;

  /// Manually initializes a BinaryMergeResult with explicit values.
  BinaryMergeResult.explicit({
    required this.mergedBytes,
    required super.hasConflict,
    required super.exitCode,
    required super.localPath,
  }) : super.explicit();

  /// The final merged bytes.
  Uint8List mergedBytes;
}
