// 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:flutter/foundation.dart';

import 'package:cocoon_service/protos.dart' show Commit, CommitStatus, RootKey, Task;

import '../logic/brooks.dart';
import '../service/cocoon.dart';
import '../service/google_authentication.dart';

/// State for the Flutter Build Dashboard.
class BuildState extends ChangeNotifier {
  BuildState({
    @required this.cocoonService,
    @required this.authService,
  }) {
    authService.addListener(notifyListeners);
  }

  /// Cocoon backend service that retrieves the data needed for this state.
  final CocoonService cocoonService;

  /// Authentication service for managing Google Sign In.
  final GoogleSignInService authService;

  /// Git branches from flutter/flutter for managing Flutter releases.
  List<String> get branches => _branches;
  List<String> _branches = <String>['master'];

  /// The current flutter/flutter git branch to show data from.
  String get currentBranch => _currentBranch;
  String _currentBranch = 'master';

  /// The current status of the commits loaded.
  List<CommitStatus> get statuses => _statuses;
  List<CommitStatus> _statuses = <CommitStatus>[];

  /// Whether or not flutter/flutter currently passes tests.
  bool get isTreeBuilding => _isTreeBuilding;
  bool _isTreeBuilding;

  /// Whether more [List<CommitStatus>] can be loaded from Cocoon.
  ///
  /// If [fetchMoreCommitStatuses] returns no data, it is assumed the last
  /// [CommitStatus] has been loaded.
  bool get moreStatusesExist => _moreStatusesExist;
  bool _moreStatusesExist = true;

  /// A [Brook] that reports when errors occur that relate to this [BuildState].
  Brook<String> get errors => _errors;
  final ErrorSink _errors = ErrorSink();

  @visibleForTesting
  static const String errorMessageFetchingStatuses = 'An error occured fetching build statuses from Cocoon';

  @visibleForTesting
  static const String errorMessageFetchingTreeStatus = 'An error occured fetching tree status from Cocoon';

  @visibleForTesting
  static const String errorMessageFetchingBranches =
      'An error occured fetching branches from flutter/flutter on Cocoon.';

  /// How often to query the Cocoon backend for the current build state.
  @visibleForTesting
  final Duration refreshRate = const Duration(seconds: 10);

  /// Timer that calls [_fetchStatusUpdates] on a set interval.
  @visibleForTesting
  @protected
  Timer refreshTimer;

  // There's no way to cancel futures in the standard library so instead we just track
  // if we've been disposed, and if so, we drop everything on the floor.
  bool _active = true;

  @override
  void addListener(VoidCallback listener) {
    if (!hasListeners) {
      _startFetchingStatusUpdates();
      assert(refreshTimer != null);
    }
    super.addListener(listener);
  }

  @override
  void removeListener(VoidCallback listener) {
    super.removeListener(listener);
    if (!hasListeners) {
      refreshTimer?.cancel();
      refreshTimer = null;
    }
  }

  /// Start a fixed interval loop that fetches build state updates based on [refreshRate].
  void _startFetchingStatusUpdates() {
    assert(refreshTimer == null);
    _fetchStatusUpdates();
    refreshTimer = Timer.periodic(refreshRate, _fetchStatusUpdates);
  }

  /// Request the latest [statuses] and [isTreeBuilding] from [CocoonService].
  ///
  /// If fetched [statuses] is not on the current branch it will be discarded.
  Future<void> _fetchStatusUpdates([Timer timer]) async {
    await Future.wait<void>(<Future<void>>[
      () async {
        final CocoonResponse<List<String>> response = await cocoonService.fetchFlutterBranches();
        if (!_active) {
          return null;
        }
        if (response.error != null) {
          _errors.send('$errorMessageFetchingBranches: ${response.error}');
        } else {
          _branches = response.data;
          notifyListeners();
        }
      }(),
      () async {
        final CocoonResponse<List<CommitStatus>> response =
            await cocoonService.fetchCommitStatuses(branch: _currentBranch);
        if (!_active) {
          return null;
        }
        if (response.error != null) {
          _errors.send('$errorMessageFetchingStatuses: ${response.error}');
        } else {
          _mergeRecentCommitStatusesWithStoredStatuses(response.data);
          notifyListeners();
        }
      }(),
      () async {
        final CocoonResponse<bool> response = await cocoonService.fetchTreeBuildStatus(branch: _currentBranch);
        if (!_active) {
          return null;
        }
        if (response.error != null) {
          _errors.send('$errorMessageFetchingTreeStatus: ${response.error}');
        } else {
          _isTreeBuilding = response.data;
          notifyListeners();
        }
      }(),
    ]);
  }

  /// Update build state to be on [branch] and erase previous branch data.
  Future<void> updateCurrentBranch(String branch) {
    _currentBranch = branch;
    _moreStatusesExist = true;
    _isTreeBuilding = null;
    _statuses = <CommitStatus>[];

    /// Clear previous branch data from the widgets
    notifyListeners();

    /// To prevent delays, make an immediate request for dashboard data.
    return _fetchStatusUpdates();
  }

  /// Handle merging status updates with the current data in [statuses].
  ///
  /// [recentStatuses] is expected to be sorted from newest commit to oldest
  /// commit. This is the same order as [statuses].
  ///
  /// If the current list of statuses is empty, [recentStatuses] is set
  /// to be the current [statuses].
  ///
  /// Otherwise, follow this algorithm:
  ///   1. Create a new [List<CommitStatus>] that is from [recentStatuses].
  ///   2. Find where [recentStatuses] does not have [CommitStatus] that
  ///      [statuses] has. This is called the [lastKnownIndex].
  ///   3. Append the range of [statuses] from ([lastKnownIndex] to the end of
  ///      statuses) to [recentStatuses]. This is the merged [statuses].
  void _mergeRecentCommitStatusesWithStoredStatuses(
    List<CommitStatus> recentStatuses,
  ) {
    if (!_statusesMatchCurrentBranch(recentStatuses)) {
      // Do not merge statueses if they are not from the current branch.
      // Happens in delayed network requests after switching branches.
      return;
    }

    /// If the current statuses is empty, no merge logic is necessary.
    /// This is used on the first call for statuses.
    if (_statuses.isEmpty) {
      _statuses = recentStatuses;
      return;
    }

    assert(_statusesInOrder(recentStatuses));
    final List<CommitStatus> mergedStatuses = List<CommitStatus>.from(recentStatuses);

    /// Bisect statuses to find the set that doesn't exist in [recentStatuses].
    final CommitStatus lastRecentStatus = recentStatuses.last;
    final int lastKnownIndex = _findCommitStatusIndex(_statuses, lastRecentStatus);

    /// If this assertion error occurs, the Cocoon backend needs to be updated
    /// to return more commit statuses. This error will only occur if there
    /// is a gap between [recentStatuses] and [statuses].
    assert(lastKnownIndex != -1);

    final int firstIndex = lastKnownIndex + 1;
    final int lastIndex = _statuses.length;

    /// If the current statuses has the same statuses as [recentStatuses],
    /// there will be no subset of remaining statuses. Instead, it will give
    /// a list with a null generated [CommitStatus]. Therefore we manually
    /// return an empty list.
    final List<CommitStatus> remainingStatuses = (firstIndex < lastIndex)
        ? _statuses
            .getRange(
              firstIndex,
              lastIndex,
            )
            .toList()
        : <CommitStatus>[];

    mergedStatuses.addAll(remainingStatuses);

    _statuses = mergedStatuses;
    assert(_statusesAreUnique(statuses));
  }

  /// Find the index in [statuses] that has [statusToFind] based on the key.
  /// Return -1 if it does not exist.
  ///
  /// The rest of the data in the [CommitStatus] can be different.
  int _findCommitStatusIndex(
    List<CommitStatus> statuses,
    CommitStatus statusToFind,
  ) {
    for (int index = 0; index < statuses.length; index += 1) {
      final CommitStatus current = _statuses[index];
      if (current.commit.key == statusToFind.commit.key) {
        return index;
      }
    }
    return -1;
  }

  Future<void> _moreStatuses;

  /// When the user reaches the end of [statuses], we load more from Cocoon
  /// to create an infinite scroll effect.
  ///
  /// This method is idempotent (calling it when it's already running will
  /// just return the same Future without kicking off more work).
  Future<void> fetchMoreCommitStatuses() {
    if (_moreStatuses != null) {
      return _moreStatuses;
    }
    _moreStatuses = _fetchMoreCommitStatusesInternal();
    _moreStatuses.whenComplete(() {
      _moreStatuses = null;
    });
    return _moreStatuses;
  }

  Future<void> _fetchMoreCommitStatusesInternal() async {
    assert(_statuses.isNotEmpty);

    final CocoonResponse<List<CommitStatus>> response = await cocoonService.fetchCommitStatuses(
      lastCommitStatus: _statuses.last,
      branch: _currentBranch,
    );
    if (!_active) {
      return;
    }
    if (response.error != null) {
      _errors.send('$errorMessageFetchingStatuses: ${response.error}');
      return;
    }
    final List<CommitStatus> newStatuses = response.data;

    /// Handle the case where release branches only have a few commits.
    if (newStatuses.isEmpty) {
      _moreStatusesExist = false;
      notifyListeners();
      return;
    }

    assert(_statusesInOrder(newStatuses));

    /// The [List<CommitStatus>] returned is the statuses that come at the end
    /// of our current list and can just be appended.
    _statuses.addAll(newStatuses);
    notifyListeners();

    assert(_statusesAreUnique(statuses));
  }

  Future<bool> rerunTask(Task task) async {
    return cocoonService.rerunTask(task, await authService.idToken);
  }

  Future<bool> downloadLog(Task task, Commit commit) async {
    return cocoonService.downloadLog(task, await authService.idToken, commit.sha);
  }

  /// Assert that [statuses] is ordered from newest commit to oldest.
  bool _statusesInOrder(List<CommitStatus> statuses) {
    for (int i = 0; i < statuses.length - 1; i++) {
      final Commit current = statuses[i].commit;
      final Commit next = statuses[i + 1].commit;

      if (current.timestamp < next.timestamp) {
        return false;
      }
    }

    return true;
  }

  /// Assert that there are no duplicate commits in [statuses].
  bool _statusesAreUnique(List<CommitStatus> statuses) {
    final Set<RootKey> uniqueStatuses = <RootKey>{};
    for (int i = 0; i < statuses.length; i += 1) {
      final Commit current = statuses[i].commit;
      if (uniqueStatuses.contains(current.key)) {
        return false;
      }
      uniqueStatuses.add(current.key);
    }
    return true;
  }

  /// Check if the latest [List<CommitStatus>] matches the current branch.
  ///
  /// When switching branches, there is potential for the previous branch data
  /// to come in. In that case, the dashboard should ignore that data.
  ///
  /// Returns true if [List<CommitStatus>] is data from the current branch.
  bool _statusesMatchCurrentBranch(List<CommitStatus> statuses) {
    assert(statuses.isNotEmpty);

    final CommitStatus exampleStatus = statuses.first;
    return exampleStatus.branch == _currentBranch;
  }

  @override
  void dispose() {
    authService.removeListener(notifyListeners);
    refreshTimer?.cancel();
    _active = false;
    super.dispose();
  }
}
