// Copyright (c) 2017 The Chromium 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:async';
import 'dart:io' as dart_io;

import 'package:file/file.dart';
import 'package:file/local.dart' as io;
import 'package:path/path.dart' as path;

import 'utils.dart';

const String _kProvisioningConfigFileEnvironmentVariable = 'FLUTTER_DEVICELAB_XCODE_PROVISIONING_CONFIG';
const String _kTestXcconfigFileName = 'TestConfig.xcconfig';
const FileSystem _fs = const io.LocalFileSystem();

/// Patches the given Xcode project adding provisioning certificates and team
/// information required to build and run the project, if
/// FLUTTER_DEVICELAB_XCODE_PROVISIONING_CONFIG is set. If it is not set,
/// we rely on automatic signing by Xcode.
Future<Null> prepareProvisioningCertificates(String flutterProjectPath) async {
  final String certificateConfig = await _readProvisioningConfigFile();
  if (certificateConfig == null) {
    // No cert config available, rely on automatic signing by Xcode.
    return;
  }

  await _patchXcconfigFilesIfNotPatched(flutterProjectPath);
  final File testXcconfig = _fs.file(path.join(flutterProjectPath, 'ios/Flutter/$_kTestXcconfigFileName'));
  await testXcconfig.writeAsString(certificateConfig);
}

Future<Null> runPodInstallForCustomPodfile(String flutterProjectPath) async {
  final String iosPath = path.join(flutterProjectPath, 'ios');
  exec('pod', <String>['install', '--project-directory=$iosPath']);
}

Future<Null> _patchXcconfigFilesIfNotPatched(String flutterProjectPath) async {
  final List<File> xcconfigFiles = <File>[
    _fs.file(path.join(flutterProjectPath, 'ios/Flutter/Flutter.xcconfig')),
    _fs.file(path.join(flutterProjectPath, 'ios/Flutter/Debug.xcconfig')),
    _fs.file(path.join(flutterProjectPath, 'ios/Flutter/Release.xcconfig'))
  ];

  bool xcconfigFileExists = false;

  for (final File file in xcconfigFiles) {
    if (await file.exists()) {
      xcconfigFileExists = true;
      const String include = '#include "$_kTestXcconfigFileName"';
      final String contents = await file.readAsString();
      final bool alreadyPatched = contents.contains(include);
      if (!alreadyPatched) {
        final IOSink patchOut = file.openWrite(mode: FileMode.APPEND);
        patchOut.writeln(); // in case EOF is not preceded by line break
        patchOut.writeln(include);
        await patchOut.close();
      }
    }
  }

  if (!xcconfigFileExists) {
    final String candidatesFormatted = xcconfigFiles.map<String>((File f) => f.path).join(', ');
    throw 'Failed to locate a xcconfig file to patch with provisioning profile '
        'info. Tried: $candidatesFormatted';
  }
}

Future<String> _readProvisioningConfigFile() async {
  void throwUsageError(String specificMessage) {
    throw '''
================================================================================
You are attempting to build an XCode project, which requires a provisioning
certificate and team information. The test framework attempted to locate an
.xcconfig file whose path is defined by the environment variable
$_kProvisioningConfigFileEnvironmentVariable.

$specificMessage
================================================================================
'''.trim();
  }

  if (!dart_io.Platform.environment.containsKey(_kProvisioningConfigFileEnvironmentVariable)) {
    print('''
$_kProvisioningConfigFileEnvironmentVariable variable is not defined in your
environment. Relying on automatic signing by Xcode...
'''.trim());
    return null;
  }

  final String filePath = dart_io.Platform.environment[_kProvisioningConfigFileEnvironmentVariable];
  final File file = _fs.file(filePath);
  if (!(await file.exists())) {
    throwUsageError('''
File not found: $filePath

It is defined by environment variable $_kProvisioningConfigFileEnvironmentVariable
'''.trim());
  }

  return file.readAsString();
}
