// 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 '../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 '../xcode_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) {
    // projectBundleId is unused for macOS apps. Use a placeholder bundle ID.
    return BuildableMacOSApp(project, 'com.example.placeholder');
  }

  /// 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.
  static 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, String projectBundleId): super(projectBundleId: projectBundleId);

  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;
}
