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

// @dart = 2.8

import 'package:meta/meta.dart';

import '../application_package.dart';
import '../base/file_system.dart';
import '../base/io.dart';
import '../base/utils.dart';
import '../build_info.dart';
import '../globals_null_migrated.dart' as globals;
import '../ios/plist_parser.dart';
import '../project.dart';

/// Tests whether a [FileSystemEntity] is an macOS bundle directory.
bool _isBundleDirectory(FileSystemEntity entity) =>
    entity is Directory && entity.path.endsWith('.app');

abstract class MacOSApp extends ApplicationPackage {
  MacOSApp({@required String projectBundleId}) : super(id: projectBundleId);

  /// Creates a new [MacOSApp] from a macOS project directory.
  factory MacOSApp.fromMacOSProject(MacOSProject project) {
    return BuildableMacOSApp(project);
  }

  /// Creates a new [MacOSApp] from an existing app bundle.
  ///
  /// `applicationBinary` is the path to the framework directory created by an
  /// Xcode build. By default, this is located under
  /// "~/Library/Developer/Xcode/DerivedData/" and contains an executable
  /// which is expected to start the application and send the observatory
  /// port over stdout.
  factory MacOSApp.fromPrebuiltApp(FileSystemEntity applicationBinary) {
    final _BundleInfo bundleInfo = _executableFromBundle(applicationBinary);
    if (bundleInfo == null) {
      return null;
    }

    return PrebuiltMacOSApp(
      bundleDir: bundleInfo.bundle,
      bundleName: bundleInfo.bundle.path,
      projectBundleId: bundleInfo.id,
      executable: bundleInfo.executable,
    );
  }

  /// Look up the executable name for a macOS application bundle.
  static _BundleInfo _executableFromBundle(FileSystemEntity applicationBundle) {
    final FileSystemEntityType entityType = globals.fs.typeSync(applicationBundle.path);
    if (entityType == FileSystemEntityType.notFound) {
      globals.printError('File "${applicationBundle.path}" does not exist.');
      return null;
    }
    Directory bundleDir;
    if (entityType == FileSystemEntityType.directory) {
      final Directory directory = globals.fs.directory(applicationBundle);
      if (!_isBundleDirectory(directory)) {
        globals.printError('Folder "${applicationBundle.path}" is not an app bundle.');
        return null;
      }
      bundleDir = globals.fs.directory(applicationBundle);
    } else {
      // Try to unpack as a zip.
      final Directory tempDir = globals.fs.systemTempDirectory.createTempSync('flutter_app.');
      try {
        globals.os.unzip(globals.fs.file(applicationBundle), tempDir);
      } on ProcessException {
        globals.printError('Invalid prebuilt macOS app. Unable to extract bundle from archive.');
        return null;
      }
      try {
        bundleDir = tempDir
            .listSync()
            .whereType<Directory>()
            .singleWhere(_isBundleDirectory);
      } on StateError {
        globals.printError('Archive "${applicationBundle.path}" does not contain a single app bundle.');
        return null;
      }
    }
    final String plistPath = globals.fs.path.join(bundleDir.path, 'Contents', 'Info.plist');
    if (!globals.fs.file(plistPath).existsSync()) {
      globals.printError('Invalid prebuilt macOS app. Does not contain Info.plist.');
      return null;
    }
    final Map<String, dynamic> propertyValues = globals.plistParser.parseFile(plistPath);
    final String id = propertyValues[PlistParser.kCFBundleIdentifierKey] as String;
    final String executableName = propertyValues[PlistParser.kCFBundleExecutable] as String;
    if (id == null) {
      globals.printError('Invalid prebuilt macOS app. Info.plist does not contain bundle identifier');
      return null;
    }
    if (executableName == null) {
      globals.printError('Invalid prebuilt macOS app. Info.plist does not contain bundle executable');
      return null;
    }
    final String executable = globals.fs.path.join(bundleDir.path, 'Contents', 'MacOS', executableName);
    if (!globals.fs.file(executable).existsSync()) {
      globals.printError('Could not find macOS binary at $executable');
    }
    return _BundleInfo(executable, id, bundleDir);
  }

  @override
  String get displayName => id;

  String applicationBundle(BuildMode buildMode);

  String executable(BuildMode buildMode);
}

class PrebuiltMacOSApp extends MacOSApp {
  PrebuiltMacOSApp({
    @required this.bundleDir,
    @required this.bundleName,
    @required this.projectBundleId,
    @required String executable,
  }) : _executable = executable,
       super(projectBundleId: projectBundleId);

  final Directory bundleDir;
  final String bundleName;
  final String projectBundleId;

  final String _executable;

  @override
  String get name => bundleName;

  @override
  String applicationBundle(BuildMode buildMode) => bundleDir.path;

  @override
  String executable(BuildMode buildMode) => _executable;
}

class BuildableMacOSApp extends MacOSApp {
  BuildableMacOSApp(this.project);

  final MacOSProject project;

  @override
  String get name => 'macOS';

  @override
  String applicationBundle(BuildMode buildMode) {
    final File appBundleNameFile = project.nameFile;
    if (!appBundleNameFile.existsSync()) {
      globals.printError('Unable to find app name. ${appBundleNameFile.path} does not exist');
      return null;
    }
    return globals.fs.path.join(
        getMacOSBuildDirectory(),
        'Build',
        'Products',
        toTitleCase(getNameForBuildMode(buildMode)),
        appBundleNameFile.readAsStringSync().trim());
  }

  @override
  String executable(BuildMode buildMode) {
    final String directory = applicationBundle(buildMode);
    if (directory == null) {
      return null;
    }
    final _BundleInfo bundleInfo = MacOSApp._executableFromBundle(globals.fs.directory(directory));
    return bundleInfo?.executable;
  }
}

class _BundleInfo {
  _BundleInfo(this.executable, this.id, this.bundle);

  final Directory bundle;
  final String executable;
  final String id;
}
