// 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:io';

import 'package:path/path.dart' as path;

import 'task_result.dart';
import 'utils.dart';

final String platformLineSep = Platform.isWindows ? '\r\n' : '\n';

final List<String> flutterAssets = <String>[
  'assets/flutter_assets/AssetManifest.json',
  'assets/flutter_assets/NOTICES.Z',
  'assets/flutter_assets/fonts/MaterialIcons-Regular.otf',
  'assets/flutter_assets/packages/cupertino_icons/assets/CupertinoIcons.ttf',
];

final List<String> debugAssets = <String>[
  'assets/flutter_assets/isolate_snapshot_data',
  'assets/flutter_assets/kernel_blob.bin',
  'assets/flutter_assets/vm_snapshot_data',
];

final List<String> baseApkFiles = <String> [
  'classes.dex',
  'AndroidManifest.xml',
];

/// Runs the given [testFunction] on a freshly generated Flutter project.
Future<void> runProjectTest(Future<void> Function(FlutterProject project) testFunction) async {
  final Directory tempDir = Directory.systemTemp.createTempSync('flutter_devicelab_gradle_plugin_test.');
  final FlutterProject project = await FlutterProject.create(tempDir, 'hello');

  try {
    await testFunction(project);
  } finally {
    rmTree(tempDir);
  }
}

/// Runs the given [testFunction] on a freshly generated Flutter plugin project.
Future<void> runPluginProjectTest(Future<void> Function(FlutterPluginProject pluginProject) testFunction) async {
  final Directory tempDir = Directory.systemTemp.createTempSync('flutter_devicelab_gradle_plugin_test.');
  final FlutterPluginProject pluginProject = await FlutterPluginProject.create(tempDir, 'aaa');

  try {
    await testFunction(pluginProject);
  } finally {
    rmTree(tempDir);
  }
}

/// Runs the given [testFunction] on a freshly generated Flutter module project.
Future<void> runModuleProjectTest(Future<void> Function(FlutterModuleProject moduleProject) testFunction) async {
  final Directory tempDir = Directory.systemTemp.createTempSync('flutter_devicelab_gradle_module_test.');
  final FlutterModuleProject moduleProject = await FlutterModuleProject.create(tempDir, 'hello_module');

  try {
    await testFunction(moduleProject);
  } finally {
    rmTree(tempDir);
  }
}

/// Returns the list of files inside an Android Package Kit.
Future<Iterable<String>> getFilesInApk(String apk) async {
  if (!File(apk).existsSync()) {
    throw TaskResult.failure(
        'Gradle did not produce an output artifact file at: $apk');
  }
  final String files = await _evalApkAnalyzer(
    <String>[
      'files',
      'list',
      apk,
    ]
  );
  return files.split('\n').map((String file) => file.substring(1).trim());
}
/// Returns the list of files inside an Android App Bundle.
Future<Iterable<String>> getFilesInAppBundle(String bundle) {
  return getFilesInApk(bundle);
}

/// Returns the list of files inside an Android Archive.
Future<Iterable<String>> getFilesInAar(String aar) {
  return getFilesInApk(aar);
}

TaskResult failure(String message, ProcessResult result) {
  print('Unexpected process result:');
  print('Exit code: ${result.exitCode}');
  print('Std out  :\n${result.stdout}');
  print('Std err  :\n${result.stderr}');
  return TaskResult.failure(message);
}

bool hasMultipleOccurrences(String text, Pattern pattern) {
  return text.indexOf(pattern) != text.lastIndexOf(pattern);
}

/// The Android home directory.
String get _androidHome {
  final String? androidHome = Platform.environment['ANDROID_HOME'] ??
      Platform.environment['ANDROID_SDK_ROOT'];
  if (androidHome == null || androidHome.isEmpty) {
    throw Exception('Environment variable `ANDROID_SDK_ROOT` is not set.');
  }
  return androidHome;
}

/// Executes an APK analyzer subcommand.
Future<String> _evalApkAnalyzer(
  List<String> args, {
  bool printStdout = false,
  String? workingDirectory,
}) async {
  final String? javaHome = await findJavaHome();
  if (javaHome == null || javaHome.isEmpty) {
    throw Exception('No JAVA_HOME set.');
  }
  final String apkAnalyzer = path
     .join(_androidHome, 'cmdline-tools', 'latest', 'bin', Platform.isWindows ? 'apkanalyzer.bat' : 'apkanalyzer');
   if (canRun(apkAnalyzer)) {
     return eval(
       apkAnalyzer,
       args,
       printStdout: printStdout,
       workingDirectory: workingDirectory,
       environment: <String, String>{
         'JAVA_HOME': javaHome,
       },
     );
   }

  final String javaBinary = path.join(javaHome, 'bin', 'java');
  assert(canRun(javaBinary));
  final String androidTools = path.join(_androidHome, 'tools');
  final String libs = path.join(androidTools, 'lib');
  assert(Directory(libs).existsSync());

  final String classSeparator =  Platform.isWindows ? ';' : ':';
  return eval(
    javaBinary,
    <String>[
      '-Dcom.android.sdklib.toolsdir=$androidTools',
      '-classpath',
      '.$classSeparator$libs${Platform.pathSeparator}*',
      'com.android.tools.apk.analyzer.ApkAnalyzerCli',
      ...args,
    ],
    printStdout: printStdout,
    workingDirectory: workingDirectory,
  );
}

/// Utility class to analyze the content inside an APK using the APK analyzer.
class ApkExtractor {
  ApkExtractor(this.apkFile);

  /// The APK.
  final File apkFile;

  bool _extracted = false;

  Set<String> _classes = const <String>{};
  Set<String> _methods = const <String>{};

  Future<void> _extractDex() async {
    if (_extracted) {
      return;
    }
    final String packages = await _evalApkAnalyzer(
      <String>[
        'dex',
        'packages',
        apkFile.path,
      ],
    );
    final List<String> lines = packages.split('\n');
    _classes = Set<String>.from(
      lines.where((String line) => line.startsWith('C'))
           .map<String>((String line) => line.split('\t').last),
    );
    assert(_classes.isNotEmpty);
    _methods = Set<String>.from(
      lines.where((String line) => line.startsWith('M'))
           .map<String>((String line) => line.split('\t').last)
    );
    assert(_methods.isNotEmpty);
    _extracted = true;
  }

  /// Returns true if the APK contains a given class.
  Future<bool> containsClass(String className) async {
    await _extractDex();
    return _classes.contains(className);
  }

  /// Returns true if the APK contains a given method.
  /// For example: io.flutter.plugins.googlemaps.GoogleMapController void onFlutterViewAttached(android.view.View)
  Future<bool> containsMethod(String methodName) async {
    await _extractDex();
    return _methods.contains(methodName);
  }
}

/// Gets the content of the `AndroidManifest.xml`.
Future<String> getAndroidManifest(String apk) async {
  return _evalApkAnalyzer(
    <String>[
      'manifest',
      'print',
      apk,
    ],
    workingDirectory: _androidHome,
  );
}

/// Checks that the classes are contained in the APK, throws otherwise.
Future<void> checkApkContainsClasses(File apk, List<String> classes) async {
  final ApkExtractor extractor = ApkExtractor(apk);
  for (final String className in classes) {
    if (!(await extractor.containsClass(className))) {
      throw Exception("APK doesn't contain class `$className`.");
    }
  }
}

/// Checks that the methods are defined in the APK, throws otherwise.
Future<void> checkApkContainsMethods(File apk, List<String> methods) async {
  final ApkExtractor extractor = ApkExtractor(apk);
  for (final String method in methods) {
    if (!(await extractor.containsMethod(method))) {
      throw Exception("APK doesn't contain method `$method`.");
    }
  }
}

class FlutterProject {
  FlutterProject(this.parent, this.name);

  final Directory parent;
  final String name;

  static Future<FlutterProject> create(Directory directory, String name) async {
    await inDirectory(directory, () async {
      await flutter('create', options: <String>['--template=app', name]);
    });
    return FlutterProject(directory, name);
  }

  String get rootPath => path.join(parent.path, name);
  String get androidPath => path.join(rootPath, 'android');
  String get iosPath => path.join(rootPath, 'ios');

  Future<void> addCustomBuildType(String name, {required String initWith}) async {
    final File buildScript = File(
      path.join(androidPath, 'app', 'build.gradle'),
    );

    buildScript.openWrite(mode: FileMode.append).write('''

android {
    buildTypes {
        $name {
            initWith $initWith
        }
    }
}
    ''');
  }

  Future<void> addGlobalBuildType(String name, {required String initWith}) async {
    final File buildScript = File(
      path.join(androidPath, 'build.gradle'),
    );

    buildScript.openWrite(mode: FileMode.append).write('''
subprojects {
  afterEvaluate {
    android {
        buildTypes {
            $name {
                initWith $initWith
            }
        }
    }
  }
}
    ''');
  }

  /// Adds a plugin to the pubspec.
  /// In pubspec, each dependency is expressed as key, value pair joined by a colon `:`.
  /// such as `plugin_a`:`^0.0.1` or `plugin_a`:`\npath: /some/path`.
  void addPlugin(String plugin, { String value = '' }) {
    final File pubspec = File(path.join(rootPath, 'pubspec.yaml'));
    String content = pubspec.readAsStringSync();
    content = content.replaceFirst(
      '${platformLineSep}dependencies:$platformLineSep',
      '${platformLineSep}dependencies:$platformLineSep  $plugin: $value$platformLineSep',
    );
    pubspec.writeAsStringSync(content, flush: true);
  }

  Future<void> getPackages() async {
    await inDirectory(Directory(rootPath), () async {
      await flutter('pub', options: <String>['get']);
    });
  }

  Future<void> addProductFlavors(Iterable<String> flavors) async {
    final File buildScript = File(
      path.join(androidPath, 'app', 'build.gradle'),
    );

    final String flavorConfig = flavors.map((String name) {
      return '''
$name {
    applicationIdSuffix ".$name"
    versionNameSuffix "-$name"
}
      ''';
    }).join('\n');

    buildScript.openWrite(mode: FileMode.append).write('''
android {
    flavorDimensions "mode"
    productFlavors {
        $flavorConfig
    }
}
    ''');
  }

  Future<void> introduceError() async {
    final File buildScript = File(
      path.join(androidPath, 'app', 'build.gradle'),
    );
    await buildScript.writeAsString((await buildScript.readAsString()).replaceAll('buildTypes', 'builTypes'));
  }

  Future<void> introducePubspecError() async {
    final File pubspec = File(
      path.join(parent.path, 'hello', 'pubspec.yaml')
    );
    final String contents = pubspec.readAsStringSync();
    final String newContents = contents.replaceFirst('# The following section is specific to Flutter.${platformLineSep}flutter:$platformLineSep', '''
flutter:
  assets:
    - lib/gallery/example_code.dart

''');
    pubspec.writeAsStringSync(newContents);
  }

  Future<void> runGradleTask(String task, {List<String>? options}) async {
    return _runGradleTask(workingDirectory: androidPath, task: task, options: options);
  }

  Future<ProcessResult> resultOfGradleTask(String task, {List<String>? options}) {
    return _resultOfGradleTask(workingDirectory: androidPath, task: task, options: options);
  }

  Future<ProcessResult> resultOfFlutterCommand(String command, List<String> options) {
    return Process.run(
      path.join(flutterDirectory.path, 'bin', Platform.isWindows ? 'flutter.bat' : 'flutter'),
      <String>[command, ...options],
      workingDirectory: rootPath,
    );
  }
}

class FlutterPluginProject {
  FlutterPluginProject(this.parent, this.name);

  final Directory parent;
  final String name;

  static Future<FlutterPluginProject> create(Directory directory, String name) async {
    await inDirectory(directory, () async {
      await flutter('create', options: <String>['--template=plugin', '--platforms=ios,android', name]);
    });
    return FlutterPluginProject(directory, name);
  }

  String get rootPath => path.join(parent.path, name);
  String get examplePath => path.join(rootPath, 'example');
  String get exampleAndroidPath => path.join(examplePath, 'android');
  String get debugApkPath => path.join(examplePath, 'build', 'app', 'outputs', 'flutter-apk', 'app-debug.apk');
  String get releaseApkPath => path.join(examplePath, 'build', 'app', 'outputs', 'flutter-apk', 'app-release.apk');
  String get releaseArmApkPath => path.join(examplePath, 'build', 'app', 'outputs', 'flutter-apk','app-armeabi-v7a-release.apk');
  String get releaseArm64ApkPath => path.join(examplePath, 'build', 'app', 'outputs', 'flutter-apk', 'app-arm64-v8a-release.apk');
  String get releaseBundlePath => path.join(examplePath, 'build', 'app', 'outputs', 'bundle', 'release', 'app.aab');
}

class FlutterModuleProject {
  FlutterModuleProject(this.parent, this.name);

  final Directory parent;
  final String name;

  static Future<FlutterModuleProject> create(Directory directory, String name) async {
    await inDirectory(directory, () async {
      await flutter('create', options: <String>['--template=module', name]);
    });
    return FlutterModuleProject(directory, name);
  }

  String get rootPath => path.join(parent.path, name);
}

Future<void> _runGradleTask({
  required String workingDirectory,
  required String task,
  List<String>? options,
}) async {
  final ProcessResult result = await _resultOfGradleTask(
      workingDirectory: workingDirectory,
      task: task,
      options: options);
  if (result.exitCode != 0) {
    print('stdout:');
    print(result.stdout);
    print('stderr:');
    print(result.stderr);
  }
  if (result.exitCode != 0)
    throw 'Gradle exited with error';
}

Future<ProcessResult> _resultOfGradleTask({
  required String workingDirectory,
  required String task,
  List<String>? options,
}) async {
  section('Find Java');
  final String? javaHome = await findJavaHome();

  if (javaHome == null)
    throw TaskResult.failure('Could not find Java');

  print('\nUsing JAVA_HOME=$javaHome');

  final List<String> args = <String>[
    'app:$task',
    ...?options,
  ];
  final String gradle = path.join(workingDirectory, Platform.isWindows ? 'gradlew.bat' : './gradlew');
  print('┌── $gradle');
  print(File(path.join(workingDirectory, gradle)).readAsLinesSync().map((String line) => '| $line').join('\n'));
  print('└─────────────────────────────────────────────────────────────────────────────────────');
  print(
    'Running Gradle:\n'
    '  Executable: $gradle\n'
    '  Arguments: ${args.join(' ')}\n'
    '  Working directory: $workingDirectory\n'
    '  JAVA_HOME: $javaHome\n'
  );
  return Process.run(
    gradle,
    args,
    workingDirectory: workingDirectory,
    environment: <String, String>{ 'JAVA_HOME': javaHome },
  );
}

/// Returns [null] if target matches [expectedTarget], otherwise returns an error message.
String? validateSnapshotDependency(FlutterProject project, String expectedTarget) {
  final File snapshotBlob = File(
      path.join(project.rootPath, 'build', 'app', 'intermediates',
          'flutter', 'debug', 'flutter_build.d'));

  assert(snapshotBlob.existsSync());
  final String contentSnapshot = snapshotBlob.readAsStringSync();
  return contentSnapshot.contains('$expectedTarget ')
    ? null : 'Dependency file should have $expectedTarget as target. Instead found $contentSnapshot';
}
