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

import 'base/file_system.dart';
import 'base/logger.dart';
import 'base/utils.dart';

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

/// A wrapper around the `.metadata` file.
class FlutterProjectMetadata {
  FlutterProjectMetadata(
    File metadataFile,
    Logger logger,
    )  : _metadataFile = metadataFile,
      _logger = logger;

  final File _metadataFile;
  final Logger _logger;

  String? get versionChannel => _versionValue('channel');
  String? get versionRevision => _versionValue('revision');

  FlutterProjectType? get projectType {
    final dynamic projectTypeYaml = _metadataValue('project_type');
    if (projectTypeYaml is String) {
      return stringToProjectType(projectTypeYaml);
    } else {
      _logger.printTrace('.metadata project_type version is malformed.');
      return null;
    }
  }

  YamlMap? _versionYaml;
  String? _versionValue(String key) {
    if (_versionYaml == null) {
      final dynamic versionYaml = _metadataValue('version');
      if (versionYaml is YamlMap) {
        _versionYaml = versionYaml;
      } else {
        _logger.printTrace('.metadata version is malformed.');
        return null;
      }
    }
    if (_versionYaml != null && _versionYaml!.containsKey(key) && _versionYaml![key] is String) {
      return _versionYaml![key] as String;
    }
    return null;
  }

  YamlMap? _metadataYaml;
  dynamic _metadataValue(String key) {
    if (_metadataYaml == null) {
      if (!_metadataFile.existsSync()) {
        return null;
      }
      dynamic metadataYaml;
      try {
        metadataYaml = loadYaml(_metadataFile.readAsStringSync());
      } on YamlException {
        // Handled in return below.
      }
      if (metadataYaml is YamlMap) {
        _metadataYaml = metadataYaml;
      } else {
        _logger.printTrace('.metadata is malformed.');
        return null;
      }
    }

    return _metadataYaml![key];
  }
}
