// 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:flutter/material.dart';
import 'package:flutter_app_icons/flutter_app_icons.dart';
import 'package:flutter_dashboard/model/branch.pb.dart';

import '../logic/brooks.dart';
import '../model/build_status_response.pb.dart';
import '../model/commit.pb.dart';
import '../model/commit_status.pb.dart';
import '../model/key.pb.dart';
import '../model/task.pb.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.
  GoogleSignInService authService;

  /// Recent branches for flutter related to releases.
  List<Branch> get branches => _branches;
  List<Branch> _branches = <Branch>[
    Branch()
      ..branch = 'master'
      ..repository = 'flutter',
  ];

  /// The active flutter branches to show data from.
  String get currentBranch => _currentBranch;
  String _currentBranch = 'master';

  /// The current repo from [repos] to show data from.
  String get currentRepo => _currentRepo;
  String _currentRepo = 'flutter';

  /// Repos in the Flutter organization this dashboard supports.
  List<String> get repos => _repos;
  List<String> _repos = <String>['flutter'];

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

  List<String> get failingTasks => _failingTasks;
  List<String> _failingTasks = <String>[];

  /// 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 occurred fetching build statuses from Cocoon';

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

  @visibleForTesting
  static const String errorMessageRerunTasks = 'An error occurred rerunning tasks from Cocoon';

  @visibleForTesting
  static const String errorMessageFetchingFailingTasks =
      'An error occurred fetching the list of failing tasks from Cocoon';

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

  @visibleForTesting
  static const String errorMessageFetchingRepos = 'An error occurred fetching repos from flutter/flutter on Cocoon.';

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

  /// 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);
    _fetchBranches();
    _fetchRepos();
    _fetchStatusUpdates();
    refreshTimer = Timer.periodic(refreshRate!, _fetchStatusUpdates);
  }

  /// Request the latest [branches] from [CocoonService].
  Future<void> _fetchBranches() async {
    final CocoonResponse<List<Branch>> response = await cocoonService.fetchFlutterBranches();

    if (response.error != null) {
      _errors.send('$errorMessageFetchingBranches: ${response.error}');
    } else {
      _branches = response.data!;
      notifyListeners();
    }
  }

  /// Request the latest [repos] from [CocoonService].
  Future<void> _fetchRepos() async {
    final CocoonResponse<List<String>> response = await cocoonService.fetchRepos();
    if (response.error != null) {
      _errors.send('$errorMessageFetchingRepos: ${response.error}');
    } else {
      _repos = response.data!;
      notifyListeners();
    }
  }

  /// 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 String queriedRepoBranch = '$currentRepo/$currentBranch';
        final CocoonResponse<List<CommitStatus>> response =
            await cocoonService.fetchCommitStatuses(branch: currentBranch, repo: currentRepo);
        if (!_active) {
          return null;
        }
        if (response.error != null) {
          _errors.send('$errorMessageFetchingStatuses: ${response.error}');
        } else if (queriedRepoBranch != '$currentRepo/$currentBranch') {
          // No-op as the dashboard shouldn't update with old data
          return;
        } else {
          _mergeRecentCommitStatusesWithStoredStatuses(response.data!);
          notifyListeners();
        }
      }(),
      () async {
        final flutterAppIconsPlugin = FlutterAppIcons();
        final String queriedRepoBranch = '$currentRepo/$currentBranch';
        final CocoonResponse<BuildStatusResponse> response = await cocoonService.fetchTreeBuildStatus(
          branch: currentBranch,
          repo: currentRepo,
        );
        if (!_active) {
          return null;
        }
        if (response.error != null) {
          _errors.send('$errorMessageFetchingTreeStatus: ${response.error}');
        } else if (queriedRepoBranch != '$currentRepo/$currentBranch') {
          // No-op as the dashboard shouldn't update with old data
          return;
        } else {
          _isTreeBuilding = response.data!.buildStatus == EnumBuildStatus.success;
          _failingTasks = response.data!.failingTasks;
          if (_isTreeBuilding == false) {
            unawaited(flutterAppIconsPlugin.setIcon(icon: 'favicon-failure.png'));
          } else {
            unawaited(flutterAppIconsPlugin.setIcon(icon: 'favicon.png'));
          }
          notifyListeners();
        }
      }(),
    ]);
  }

  /// Update build state to be on [repo] and erase previous data.
  void updateCurrentRepoBranch(String repo, String branch) {
    if (currentRepo == repo && currentBranch == branch) {
      // Do nothing if the repo hasn't changed.
      return;
    }
    _currentRepo = repo;
    _currentBranch = branch;

    _moreStatusesExist = true;
    _isTreeBuilding = null;
    _failingTasks = <String>[];
    _statuses = <CommitStatus>[];

    _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 statuses 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,
      repo: currentRepo,
    );
    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> refreshGitHubCommits() async => cocoonService.vacuumGitHubCommits(await authService.idToken);

  Future<bool> rerunTask(Task task) async {
    final CocoonResponse<bool> response = await cocoonService.rerunTask(task, await authService.idToken, _currentRepo);
    if (response.error != null) {
      _errors.send('$errorMessageRerunTasks: ${response.error}');
      return false;
    }
    return true;
  }

  /// 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();
  }
}
