// 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 'package:yaml/yaml.dart';

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

/// Represents subdirectories of the flutter project that can be independently created.
///
/// This includes each supported platform as well as a component that represents the
/// root directory of the project.
enum FlutterProjectComponent {
  root,
  android,
  ios,
  linux,
  macos,
  web,
  windows,
  fuchsia,
}

extension SupportedPlatformExtension on SupportedPlatform {
  FlutterProjectComponent toFlutterProjectComponent() {
    final String platformName = toString().split('.').last;
    return FlutterProjectComponent.values.firstWhere(
        (FlutterProjectComponent e) =>
            e.toString() == 'FlutterProjectComponent.$platformName');
  }
}

extension FlutterProjectComponentExtension on FlutterProjectComponent {
  SupportedPlatform? toSupportedPlatform() {
    final String platformName = toString().split('.').last;
    if (platformName == 'root') {
      return null;
    }
    return SupportedPlatform.values.firstWhere((SupportedPlatform e) =>
        e.toString() == 'SupportedPlatform.$platformName');
  }
}

enum FlutterProjectType {
  /// This is the default project with the user-managed host code.
  /// It is different than the "module" template in that it exposes and doesn't
  /// manage the platform code.
  app,

  /// A List/Detail app template that follows community best practices.
  skeleton,

  /// The is a project that has managed platform host code. It is an application with
  /// ephemeral .ios and .android directories that can be updated automatically.
  module,

  /// This is a Flutter Dart package project. It doesn't have any native
  /// components, only Dart.
  package,

  /// This is a native plugin project.
  plugin,

  /// This is an FFI native plugin project.
  ffiPlugin,
}

String flutterProjectTypeToString(FlutterProjectType? type) {
  if (type == null) {
    return '';
  }
  if (type == FlutterProjectType.ffiPlugin) {
    return 'plugin_ffi';
  }
  return getEnumName(type);
}

FlutterProjectType? stringToProjectType(String value) {
  FlutterProjectType? result;
  for (final FlutterProjectType type in FlutterProjectType.values) {
    if (value == flutterProjectTypeToString(type)) {
      result = type;
      break;
    }
  }
  return result;
}

/// Verifies the expected yaml keys are present in the file.
bool _validateMetadataMap(
    YamlMap map, Map<String, Type> validations, Logger logger) {
  bool isValid = true;
  for (final MapEntry<String, Object> entry in validations.entries) {
    if (!map.keys.contains(entry.key)) {
      isValid = false;
      logger.printTrace('The key `${entry.key}` was not found');
      break;
    }
    final Object? metadataValue = map[entry.key];
    if (metadataValue.runtimeType != entry.value) {
      isValid = false;
      logger.printTrace(
          'The value of key `${entry.key}` in .metadata was expected to be ${entry.value} but was ${metadataValue.runtimeType}');
      break;
    }
  }
  return isValid;
}

/// A wrapper around the `.metadata` file.
class FlutterProjectMetadata {
  /// Creates a MigrateConfig by parsing an existing .migrate_config yaml file.
  FlutterProjectMetadata(this.file, Logger logger)
      : _logger = logger,
        migrateConfig = MigrateConfig() {
    if (!file.existsSync()) {
      _logger.printTrace('No .metadata file found at ${file.path}.');
      // Create a default empty metadata.
      return;
    }
    Object? yamlRoot;
    try {
      yamlRoot = loadYaml(file.readAsStringSync());
    } on YamlException {
      // Handled in _validate below.
    }
    if (yamlRoot is! YamlMap) {
      _logger
          .printTrace('.metadata file at ${file.path} was empty or malformed.');
      return;
    }
    if (_validateMetadataMap(
        yamlRoot, <String, Type>{'version': YamlMap}, _logger)) {
      final Object? versionYamlMap = yamlRoot['version'];
      if (versionYamlMap is YamlMap &&
          _validateMetadataMap(
              versionYamlMap,
              <String, Type>{
                'revision': String,
                'channel': String,
              },
              _logger)) {
        _versionRevision = versionYamlMap['revision'] as String?;
        _versionChannel = versionYamlMap['channel'] as String?;
      }
    }
    if (_validateMetadataMap(
        yamlRoot, <String, Type>{'project_type': String}, _logger)) {
      _projectType = stringToProjectType(yamlRoot['project_type'] as String);
    }
    final Object? migrationYaml = yamlRoot['migration'];
    if (migrationYaml is YamlMap) {
      migrateConfig.parseYaml(migrationYaml, _logger);
    }
  }

  /// Creates a FlutterProjectMetadata by explicitly providing all values.
  FlutterProjectMetadata.explicit({
    required this.file,
    required String? versionRevision,
    required String? versionChannel,
    required FlutterProjectType? projectType,
    required this.migrateConfig,
    required Logger logger,
  })  : _logger = logger,
        _versionChannel = versionChannel,
        _versionRevision = versionRevision,
        _projectType = projectType;

  /// The name of the config file.
  static const String kFileName = '.metadata';

  String? _versionRevision;
  String? get versionRevision => _versionRevision;

  String? _versionChannel;
  String? get versionChannel => _versionChannel;

  FlutterProjectType? _projectType;
  FlutterProjectType? get projectType => _projectType;

  /// Metadata and configuration for the migrate command.
  MigrateConfig migrateConfig;

  final Logger _logger;

  final File file;

  /// Writes the .migrate_config file in the provided project directory's platform subdirectory.
  ///
  /// We write the file manually instead of with a template because this
  /// needs to be able to write the .migrate_config file into legacy apps.
  void writeFile({File? outputFile}) {
    outputFile = outputFile ?? file;
    if (outputFile == null) {
      // In-memory FlutterProjectMetadata instances requires an output file to
      // be passed or specified in the constructor.
      throw const FileSystemException(
          'No outputFile specified to write .metadata to. Initialize with a file or provide one when writing.');
    }
    outputFile
      ..createSync(recursive: true)
      ..writeAsStringSync(toString(), flush: true);
  }

  @override
  String toString() {
    return '''
# This file tracks properties of this Flutter project.
# Used by Flutter tool to assess capabilities and perform upgrades etc.
#
# This file should be version controlled.

version:
  revision: $_versionRevision
  channel: $_versionChannel

project_type: ${flutterProjectTypeToString(projectType)}
${migrateConfig.getOutputFileString()}''';
  }

  void populate({
    List<SupportedPlatform>? platforms,
    required Directory projectDirectory,
    String? currentRevision,
    String? createRevision,
    bool create = true,
    bool update = true,
    required Logger logger,
  }) {
    migrateConfig.populate(
      platforms: platforms,
      projectDirectory: projectDirectory,
      currentRevision: currentRevision,
      createRevision: createRevision,
      create: create,
      update: update,
      logger: logger,
    );
  }

  /// Finds the fallback revision to use when no base revision is found in the migrate config.
  String getFallbackBaseRevision(Logger logger, String frameworkRevision) {
    // Use the .metadata file if it exists.
    if (versionRevision != null) {
      return versionRevision!;
    }
    return frameworkRevision;
  }
}

/// Represents the migrate command metadata section of a .metadata file.
///
/// This file tracks the flutter sdk git hashes of the last successful migration ('base') and
/// the version the project was created with.
///
/// Each platform tracks a different set of revisions because flutter create can be
/// used to add support for new platforms, so the base and create revision may not always be the same.
class MigrateConfig {
  MigrateConfig(
      {Map<FlutterProjectComponent, MigratePlatformConfig>? platformConfigs,
      this.unmanagedFiles = kDefaultUnmanagedFiles})
      : platformConfigs = platformConfigs ??
            <FlutterProjectComponent, MigratePlatformConfig>{};

  /// A mapping of the files that are unmanaged by defult for each platform.
  static const List<String> kDefaultUnmanagedFiles = <String>[
    'lib/main.dart',
    'ios/Runner.xcodeproj/project.pbxproj',
  ];

  /// The metadata for each platform supported by the project.
  final Map<FlutterProjectComponent, MigratePlatformConfig> platformConfigs;

  /// A list of paths relative to this file the migrate tool should ignore.
  ///
  /// These files are typically user-owned files that should not be changed.
  List<String> unmanagedFiles;

  bool get isEmpty =>
      platformConfigs.isEmpty &&
      (unmanagedFiles.isEmpty || unmanagedFiles == kDefaultUnmanagedFiles);

  /// Parses the project for all supported platforms and populates the [MigrateConfig]
  /// to reflect the project.
  void populate({
    List<SupportedPlatform>? platforms,
    required Directory projectDirectory,
    String? currentRevision,
    String? createRevision,
    bool create = true,
    bool update = true,
    required Logger logger,
  }) {
    final FlutterProject flutterProject = FlutterProject(projectDirectory);
    platforms ??= flutterProject.getSupportedPlatforms();

    final List<FlutterProjectComponent> components =
        <FlutterProjectComponent>[];
    for (final SupportedPlatform platform in platforms) {
      components.add(platform.toFlutterProjectComponent());
    }
    components.add(FlutterProjectComponent.root);
    for (final FlutterProjectComponent component in components) {
      if (platformConfigs.containsKey(component)) {
        if (update) {
          platformConfigs[component]!.baseRevision = currentRevision;
        }
      } else {
        if (create) {
          platformConfigs[component] = MigratePlatformConfig(
              component: component,
              createRevision: createRevision,
              baseRevision: currentRevision);
        }
      }
    }
  }

  /// Returns the string that should be written to the .metadata file.
  String getOutputFileString() {
    String unmanagedFilesString = '';
    for (final String path in unmanagedFiles) {
      unmanagedFilesString += "\n    - '$path'";
    }

    String platformsString = '';
    for (final MapEntry<FlutterProjectComponent, MigratePlatformConfig> entry
        in platformConfigs.entries) {
      platformsString +=
          '\n    - platform: ${entry.key.toString().split('.').last}\n      create_revision: ${entry.value.createRevision == null ? 'null' : "${entry.value.createRevision}"}\n      base_revision: ${entry.value.baseRevision == null ? 'null' : "${entry.value.baseRevision}"}';
    }

    return isEmpty
        ? ''
        : '''

# Tracks metadata for the flutter migrate command
migration:
  platforms:$platformsString

  # User provided section

  # List of Local paths (relative to this file) that should be
  # ignored by the migrate tool.
  #
  # Files that are not part of the templates will be ignored by default.
  unmanaged_files:$unmanagedFilesString
''';
  }

  /// Parses and validates the `migration` section of the .metadata file.
  void parseYaml(YamlMap map, Logger logger) {
    final Object? platformsYaml = map['platforms'];
    if (_validateMetadataMap(
        map, <String, Type>{'platforms': YamlList}, logger)) {
      if (platformsYaml is YamlList && platformsYaml.isNotEmpty) {
        for (final YamlMap platformYamlMap
            in platformsYaml.whereType<YamlMap>()) {
          if (_validateMetadataMap(
              platformYamlMap,
              <String, Type>{
                'platform': String,
                'create_revision': String,
                'base_revision': String,
              },
              logger)) {
            final FlutterProjectComponent component = FlutterProjectComponent
                .values
                .firstWhere((FlutterProjectComponent val) =>
                    val.toString() ==
                    'FlutterProjectComponent.${platformYamlMap['platform'] as String}');
            platformConfigs[component] = MigratePlatformConfig(
              component: component,
              createRevision: platformYamlMap['create_revision'] as String?,
              baseRevision: platformYamlMap['base_revision'] as String?,
            );
          } else {
            // malformed platform entry
            continue;
          }
        }
      }
    }
    if (_validateMetadataMap(
        map, <String, Type>{'unmanaged_files': YamlList}, logger)) {
      final Object? unmanagedFilesYaml = map['unmanaged_files'];
      if (unmanagedFilesYaml is YamlList && unmanagedFilesYaml.isNotEmpty) {
        unmanagedFiles =
            List<String>.from(unmanagedFilesYaml.value.cast<String>());
      }
    }
  }
}

/// Holds the revisions for a single platform for use by the flutter migrate command.
class MigratePlatformConfig {
  MigratePlatformConfig(
      {required this.component, this.createRevision, this.baseRevision});

  /// The platform this config describes.
  FlutterProjectComponent component;

  /// The Flutter SDK revision this platform was created by.
  ///
  /// Null if the initial create git revision is unknown.
  final String? createRevision;

  /// The Flutter SDK revision this platform was last migrated by.
  ///
  /// Null if the project was never migrated or the revision is unknown.
  String? baseRevision;

  bool equals(MigratePlatformConfig other) {
    return component == other.component &&
        createRevision == other.createRevision &&
        baseRevision == other.baseRevision;
  }
}
