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

// @dart = 2.6

import 'dart:convert';
import 'dart:io';

import 'package:metrics_center/metrics_center.dart';
import 'package:path/path.dart' as p;

Future<ProcessResult> runGit(
  List<String> args, {
  String processWorkingDir,
}) async {
  return Process.run(
    'git',
    args,
    workingDirectory: processWorkingDir,
    runInShell: true,
  );
}

Future<List<String>> getGitLog() async {
  final String gitRoot = p.absolute('../..');
  // Somehow gitDir.currentBranch() doesn't work in Cirrus with "fatal: 'HEAD' -
  // not a valid ref". Therefore, we use "git log" to get the revision manually.
  final ProcessResult logResult = await runGit(
    <String>['log', '--pretty=format:%H %ct', '-n', '1'],
    processWorkingDir: gitRoot,
  );
  if (logResult.exitCode != 0) {
    throw 'Unexpected exit code ${logResult.exitCode}';
  }
  return logResult.stdout.toString().trim().split(' ');
}

class PointsAndDate {
  PointsAndDate(this.points, this.date);

  final List<FlutterEngineMetricPoint> points;
  final String date;
}

Future<PointsAndDate> parse(String jsonFileName) async {
  final List<String> gitLog = await getGitLog();
  final String gitRevision = gitLog[0];
  final String gitCommitDate = gitLog[1];
  final List<MetricPoint> rawPoints = await GoogleBenchmarkParser.parse(
    jsonFileName,
  );
  final List<FlutterEngineMetricPoint> points = <FlutterEngineMetricPoint>[];
  for (final MetricPoint rawPoint in rawPoints) {
    points.add(FlutterEngineMetricPoint(
      rawPoint.tags[kNameKey],
      rawPoint.value,
      gitRevision,
      moreTags: rawPoint.tags,
    ));
  }
  return PointsAndDate(points, gitCommitDate);
}

Future<FlutterDestination> connectFlutterDestination() async {
  const String kTokenPath = 'TOKEN_PATH';
  const String kGcpProject = 'GCP_PROJECT';
  final Map<String, String> env = Platform.environment;
  final bool isTesting = env['IS_TESTING'] == 'true';
  if (env.containsKey(kTokenPath) && env.containsKey(kGcpProject)) {
    return FlutterDestination.makeFromAccessToken(
      File(env[kTokenPath]).readAsStringSync(),
      env[kGcpProject],
      isTesting: isTesting,
    );
  }
  return FlutterDestination.makeFromCredentialsJson(
    jsonDecode(Platform.environment['BENCHMARK_GCP_CREDENTIALS'])
        as Map<String, dynamic>,
    isTesting: isTesting,
  );
}

Future<void> main(List<String> args) async {
  if (args.length != 1) {
    throw 'Must have one argument: <benchmark_json_file>';
  }
  final PointsAndDate pointsAndDate = await parse(args[0]);

  // The data will be sent to the Datastore of the GCP project specified through
  // environment variable BENCHMARK_GCP_CREDENTIALS, or TOKEN_PATH/GCP_PROJECT.
  // The engine Cirrus job has currently configured the GCP project to
  // flutter-cirrus for test. We'll eventually migrate to flutter-infra project
  // once the test is done.
  final FlutterDestination destination = await connectFlutterDestination();
  await destination.update(
    pointsAndDate.points,
    DateTime.fromMillisecondsSinceEpoch(
      int.parse(pointsAndDate.date) * 1000,
      isUtc: true,
    ),
  );
}
