// Copyright 2019 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 'dart:async';

import 'package:appengine/appengine.dart';
import 'package:cocoon_service/cocoon_service.dart';
import 'package:graphql/client.dart';
import 'package:meta/meta.dart';

import '../datastore/cocoon_config.dart';
import '../foundation/providers.dart';
import '../foundation/typedefs.dart';
import '../foundation/utils.dart';
import '../model/appengine/task.dart';
import '../request_handling/api_request_handler.dart';
import '../request_handling/authentication.dart';
import '../request_handling/body.dart';
import '../request_handling/exceptions.dart';
import '../service/datastore.dart';
import 'refresh_cirrus_status_queries.dart';

/// Refer all cirrus build statuses at: https://github.com/cirruslabs/cirrus-ci-web/blob/master/schema.graphql#L120
const List<String> kCirrusFailedStates = <String>[
  'ABORTED',
  'FAILED',
];
const List<String> kCirrusInProgressStates = <String>[
  'CREATED',
  'TRIGGERED',
  'SCHEDULED',
  'EXECUTING',
  'PAUSED'
];

@immutable
class RefreshCirrusStatus extends ApiRequestHandler<Body> {
  const RefreshCirrusStatus(
    Config config,
    AuthenticationProvider authenticationProvider, {
    @visibleForTesting DatastoreServiceProvider datastoreProvider,
    @visibleForTesting
        this.branchHttpClientProvider = Providers.freshHttpClient,
    @visibleForTesting this.gitHubBackoffCalculator = twoSecondLinearBackoff,
  })  : datastoreProvider =
            datastoreProvider ?? DatastoreService.defaultProvider,
        assert(branchHttpClientProvider != null),
        assert(gitHubBackoffCalculator != null),
        super(config: config, authenticationProvider: authenticationProvider);

  final DatastoreServiceProvider datastoreProvider;
  final HttpClientProvider branchHttpClientProvider;
  final GitHubBackoffCalculator gitHubBackoffCalculator;

  @override
  Future<Body> get() async {
    final DatastoreService datastore = datastoreProvider(config.db);
    final GraphQLClient client = await config.createCirrusGraphQLClient();
    const int commitLimit = 15;

    for (String branch in await config.flutterBranches) {
      await for (FullTask task in datastore.queryRecentTasks(
          taskName: 'cirrus', commitLimit: commitLimit, branch: branch)) {
        final String sha = task.commit.sha;
        final String existingTaskStatus = task.task.status;

        log.debug(
            'Found Cirrus task for branch $branch, commit $sha, with existing status $existingTaskStatus');

        const String name = 'flutter';
        final List<CirrusResult> cirrusResults =
            await queryCirrusGraphQL(sha, client, log, name);

        /// Get cirrus task statuses for [task.commit.branch] and [sha].
        final List<String> statuses =
            _getStatuses(cirrusResults, task.commit.branch, sha);

        /// Calculate overall new task status based on cirrus results.
        final String newTaskStatus = _getNewTaskStatus(statuses, task);

        if (newTaskStatus == existingTaskStatus) {
          continue;
        }
        task.task.status = newTaskStatus;
        await datastore.insert(<Task>[task.task]);
      }
    }
    return Body.empty;
  }

  String _getNewTaskStatus(List<String> statuses, FullTask task) {
    String newTaskStatus;
    if (statuses.isEmpty) {
      newTaskStatus = Task.statusNew;
    } else if (statuses.any(kCirrusFailedStates.contains)) {
      newTaskStatus = Task.statusFailed;
      task.task.endTimestamp = DateTime.now().millisecondsSinceEpoch;
    } else if (statuses.any(kCirrusInProgressStates.contains)) {
      newTaskStatus = Task.statusInProgress;
    } else {
      newTaskStatus = Task.statusSucceeded;
      task.task.endTimestamp = DateTime.now().millisecondsSinceEpoch;
    }
    return newTaskStatus;
  }

  List<String> _getStatuses(
      List<CirrusResult> cirrusResults, String branch, String sha) {
    final List<String> statuses = <String>[];

    /// Multiple branches may exist for same commit.
    /// Update only when branches match
    if (!cirrusResults
        .any((CirrusResult cirrusResult) => cirrusResult.branch == branch)) {
      return statuses;
    }
    for (Map<String, dynamic> runStatus in cirrusResults
        .firstWhere(
            (CirrusResult cirrusResult) => cirrusResult.branch == branch)
        .tasks) {
      final String status = runStatus['status'] as String;
      final String taskName = runStatus['name'] as String;
      log.debug('Found Cirrus build status for $sha: $taskName ($status)');
      statuses.add(status);
    }
    return statuses;
  }
}

Future<List<CirrusResult>> queryCirrusGraphQL(
  String sha,
  GraphQLClient client,
  Logging log,
  String name,
) async {
  assert(client != null);
  const String owner = 'flutter';
  final QueryResult result = await client.query(
    QueryOptions(
      document: cirusStatusQuery,
      fetchPolicy: FetchPolicy.noCache,
      variables: <String, dynamic>{
        'owner': owner,
        'name': name,
        'SHA': sha,
      },
    ),
  );

  if (result.hasErrors) {
    for (GraphQLError error in result.errors) {
      log.error(error.toString());
    }
    throw const BadRequestException('GraphQL query failed');
  }

  final List<Map<String, dynamic>> tasks = <Map<String, dynamic>>[];
  final List<CirrusResult> cirrusResults = <CirrusResult>[];
  String branch;
  if (result.data == null) {
    cirrusResults.add(CirrusResult(branch, tasks));
    return cirrusResults;
  }
  try {
    final List<dynamic> searchBuilds =
        result.data['searchBuilds'] as List<dynamic>;
    for (dynamic searchBuild in searchBuilds) {
      tasks.clear();
      tasks.addAll((searchBuild['latestGroupTasks'] as List<dynamic>)
          .cast<Map<String, dynamic>>());
      branch = searchBuild['branch'] as String;
      cirrusResults.add(CirrusResult(branch, tasks));
    }
  } catch (_) {
    log.debug(
        'Did not receive expected result from Cirrus, sha $sha may not be executing Cirrus tasks.');
  }
  return cirrusResults;
}

class CirrusResult {
  const CirrusResult(this.branch, this.tasks) : assert(tasks != null);

  final String branch;
  final List<Map<String, dynamic>> tasks;
}
