// Copyright (c) 2020, the Dart project authors.  Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.

// This script is used by the bisection mechanism to update the blamelists
// of active, non-approved failures which include the commit of the current
// bisection build.

import 'dart:io';

import 'package:args/args.dart';
import 'package:test_runner/bot_results.dart';

import 'lib/src/firestore.dart';

const newTest = 'new test';
const skippedTest = 'skipped';

const maxAttempts = 20;

late FirestoreDatabase database;

class ResultRecord {
  final Map<String, dynamic> data;

  ResultRecord(this.data);

  Map field(String name) => (data['fields'] as Map)[name];

  int get blamelistStartIndex {
    return int.parse(field('blamelist_start_index')['integerValue']);
  }

  set blamelistStartIndex(int index) {
    field('blamelist_start_index')['integerValue'] = '$index';
  }

  int get blamelistEndIndex {
    return int.parse(field('blamelist_end_index')['integerValue']);
  }

  String get result => field('result')['stringValue'] /*!*/;

  String get previousResult => field('previous_result')['stringValue'] /*!*/;

  String get name => field('name')['stringValue'] /*!*/;

  String get updateTime => data['updateTime'] /*!*/;
}

Query unapprovedActiveFailuresQuery(String configuration) {
  return Query(
      'results',
      CompositeFilter('AND', [
        Field('approved').equals(Value.boolean(false)),
        // TODO(karlklose): also search for inactive failures?
        Field('active_configurations').contains(Value.string(configuration)),
        // TODO(karlklose): add index to check for blamelist_start_index < ?
      ]));
}

Future<int> getCommitIndex(String commit) async {
  try {
    var document =
        (await database.getDocument('commits', commit)).cast<String, dynamic>();
    var index = (document['fields'] as Map)['index'] as Map;
    if (index['integerValue'] == null) {
      throw Exception('Expected an integer, but got "$index"');
    }
    return int.parse(index['integerValue']);
  } catch (exception) {
    print('Could not retrieve index for commit "$commit".\n');
    rethrow;
  }
}

/// Compute if the record should be updated based on the outcomes in the
/// result record and the new test result.
bool shouldUpdateRecord(ResultRecord resultRecord, Result? testResult) {
  if (testResult == null || !testResult.matches) {
    return false;
  }
  var baseline = testResult.expectation.toLowerCase();
  if (resultRecord.previousResult.toLowerCase() != baseline) {
    // Currently we only support the case where a bisection run improves the
    // accuracy of a "Green" -> "Red" result record.
    return false;
  }
  if (resultRecord.result.toLowerCase() == newTest ||
      resultRecord.result.toLowerCase() == skippedTest) {
    // Skipped tests are often configuration dependent, so it could be wrong
    // to generalize their effect for the result record to different
    // configurations.
    return false;
  }
  return true;
}

Future<void> updateBlameLists(String configuration, String commit,
    Map<String, Map<String, dynamic>> testResults) async {
  int commitIndex = await getCommitIndex(commit);
  var query = unapprovedActiveFailuresQuery(configuration);
  bool needsRetry;
  int attempts = 0;
  do {
    needsRetry = false;
    var documentPaths = (await database.runQuery(query))
        .cast<Map>()
        .where((result) => result['document'] != null)
        .map((result) => (result['document'] as Map)['name'] as String);
    for (var documentPath in documentPaths) {
      database.beginTransaction();
      var documentName = documentPath.split('/').last;
      final docMap = await database.getDocument('results', documentName);
      var result = ResultRecord(docMap.cast<String, dynamic>());
      if (commitIndex < result.blamelistStartIndex ||
          commitIndex >= result.blamelistEndIndex) {
        continue;
      }
      String name = result.name;
      var testResultData = testResults['$configuration:$name'];
      var testResult =
          testResultData != null ? Result.fromMap(testResultData) : null;
      if (!shouldUpdateRecord(result, testResult)) {
        continue;
      }
      print('Found result record: $configuration:${result.name}: '
          '${result.previousResult} -> ${result.result} '
          'in ${result.blamelistStartIndex}..${result.blamelistEndIndex} '
          'to update with ${testResult?.outcome} at $commitIndex.');
      // We found a result representation for this test and configuration whose
      // blamelist includes this results' commit but whose outcome is different
      // then the outcome in the provided test results.
      // This means that this commit should not be part of the result
      // representation and we can update the lower bound of the commit range
      // and the previous result.
      var newStartIndex = commitIndex + 1;
      if (newStartIndex > result.blamelistEndIndex) {
        print('internal error: inconsistent results; skipping results entry');
        continue;
      }
      result.blamelistStartIndex = newStartIndex;
      var updateIndex = Update(['blamelist_start_index'], result.data);
      if (!await database.commit(writes: [updateIndex])) {
        // Committing the change to the database had a conflict, retry.
        needsRetry = true;
        if (++attempts == maxAttempts) {
          throw Exception('Exceeded maximum retry attempts ($maxAttempts).');
        }
        print('Transaction failed, trying again!');
      }
    }
  } while (needsRetry);
}

void main(List<String> arguments) async {
  var parser = ArgParser()
    ..addOption('auth-token',
        abbr: 'a',
        help: 'path to a file containing the gcloud auth token (required)')
    ..addOption('results',
        abbr: 'r',
        help: 'path to a file containing the test results (required)')
    ..addFlag('staging', abbr: 's', help: 'use staging database');
  var options = parser.parse(arguments);
  if (options.rest.isNotEmpty ||
      options.option('results') == null ||
      options.option('auth-token') == null) {
    print(parser.usage);
    exit(1);
  }
  var results = await loadResultsMap(options.option('results')!);
  if (results.isEmpty) {
    print("No test results provided, nothing to update.");
    return;
  }
  // Pick an arbitrary result entry to find configuration and commit hash.
  var firstResult = Result.fromMap(results.values.first);
  var commit = firstResult.commitHash!;
  var configuration = firstResult.configuration;
  var project = options.flag('staging') ? 'dart-ci-staging' : 'dart-ci';
  database = FirestoreDatabase(
      project, await readGcloudAuthToken(options.option('auth-token')!));
  await updateBlameLists(configuration, commit, results);
  database.closeClient();
}
