// Copyright 2022 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:auto_submit/service/log.dart';
import 'package:github/github.dart';

/// If a pull request was behind the tip of tree by _kBehindToT commits
/// then the bot tries to rebase it
const int _kBehindToT = 10;

/// [GithubService] handles communication with the GitHub API.
class GithubService {
  GithubService(this.github);

  final GitHub github;

  /// Retrieves check runs with the ref.
  Future<List<CheckRun>> getCheckRuns(
    RepositorySlug slug,
    String ref,
  ) async {
    return await github.checks.checkRuns.listCheckRunsForRef(slug, ref: ref).toList();
  }

  Future<List<CheckRun>> getCheckRunsFiltered({
    required RepositorySlug slug,
    required String ref,
    String? checkName,
    CheckRunStatus? status,
    CheckRunFilter? filter,
  }) async {
    return await github.checks.checkRuns
        .listCheckRunsForRef(
          slug,
          ref: ref,
          checkName: checkName,
          status: status,
          filter: filter,
        )
        .toList();
  }

  /// Fetches the specified commit.
  Future<RepositoryCommit> getCommit(RepositorySlug slug, String sha) async {
    return await github.repositories.getCommit(slug, sha);
  }

  Future<List<PullRequestFile>> getPullRequestFiles(RepositorySlug slug, PullRequest pullRequest) async {
    final int? pullRequestId = pullRequest.number;
    final List<PullRequestFile> listPullRequestFiles = [];

    if (pullRequestId == null) {
      return listPullRequestFiles;
    }

    final Stream<PullRequestFile> pullRequestFiles = github.pullRequests.listFiles(slug, pullRequestId);

    await for (PullRequestFile file in pullRequestFiles) {
      listPullRequestFiles.add(file);
    }

    return listPullRequestFiles;
  }

  /// Create a new issue in github.
  Future<Issue> createIssue({
    required RepositorySlug slug,
    required String title,
    required String body,
    List<String>? labels,
    String? assignee,
    List<String>? assignees,
    String? state,
  }) async {
    final IssueRequest issueRequest = IssueRequest(
      title: title,
      body: body,
      labels: labels,
      assignee: assignee,
      assignees: assignees,
      state: state,
    );
    return await github.issues.create(slug, issueRequest);
  }

  Future<Issue> getIssue({
    required RepositorySlug slug,
    required int issueNumber,
  }) async {
    return await github.issues.get(slug, issueNumber);
  }

  /// Fetches the specified pull request.
  Future<PullRequest> getPullRequest(RepositorySlug slug, int pullRequestNumber) async {
    return await github.pullRequests.get(slug, pullRequestNumber);
  }

  /// Compares two commits to fetch diff.
  ///
  /// The response will include details on the files that were changed between the two commits.
  /// Relevant APIs: https://docs.github.com/en/rest/reference/commits#compare-two-commits
  Future<GitHubComparison> compareTwoCommits(RepositorySlug slug, String refBase, String refHead) async {
    return await github.repositories.compareCommits(slug, refBase, refHead);
  }

  /// Removes a lable for a pull request.
  Future<bool> removeLabel(RepositorySlug slug, int issueNumber, String label) async {
    return await github.issues.removeLabelForIssue(slug, issueNumber, label);
  }

  /// Create a comment for a pull request.
  Future<IssueComment> createComment(
    RepositorySlug slug,
    int issueNumber,
    String body,
  ) async {
    return await github.issues.createComment(slug, issueNumber, body);
  }

  /// Update a pull request branch
  Future<bool> updateBranch(RepositorySlug slug, int number, String headSha) async {
    final response = await github.request(
      'PUT',
      '/repos/${slug.fullName}/pulls/$number/update-branch',
      body: GitHubJson.encode({'expected_head_sha': headSha}),
    );
    return response.statusCode == StatusCodes.ACCEPTED;
  }

  /// Get a list of all the issue comments for a specific issue.
  ///
  /// Note that these are different from review comments.
  Future<List<IssueComment>> listIssueComments(
    RepositorySlug slug,
    int issueNumber,
  ) async {
    return github.issues.listCommentsByIssue(slug, issueNumber).toList();
  }

  /// Merges a pull request according to the MergeMethod type. Current supported
  /// merge method types are merge, rebase and squash.
  Future<PullRequestMerge> mergePullRequest(
    RepositorySlug slug,
    int number, {
    String? commitMessage,
    MergeMethod mergeMethod = MergeMethod.merge,
    String? requestSha,
  }) async {
    return await github.pullRequests.merge(
      slug,
      number,
      message: commitMessage,
      mergeMethod: mergeMethod,
      requestSha: requestSha,
    );
  }

  /// Automerges a given pull request with HEAD to ensure the commit is not in conflicting state.
  Future<void> autoMergeBranch(PullRequest pullRequest) async {
    final RepositorySlug slug = pullRequest.base!.repo!.slug();
    final int prNumber = pullRequest.number!;
    final RepositoryCommit totCommit = await getCommit(slug, 'HEAD');
    final GitHubComparison comparison = await compareTwoCommits(slug, totCommit.sha!, pullRequest.base!.sha!);
    if (comparison.behindBy! >= _kBehindToT) {
      log.info('The current branch is behind by ${comparison.behindBy} commits.');
      final String headSha = pullRequest.head!.sha!;
      await updateBranch(slug, prNumber, headSha);
    }
  }

  /// Compare the filesets of the current pull request and the original pull
  /// request that is being reverted.
  Future<bool> comparePullRequests(RepositorySlug repositorySlug, PullRequest revert, PullRequest current) async {
    final List<PullRequestFile> originalPullRequestFiles = await getPullRequestFiles(repositorySlug, revert);
    final List<PullRequestFile> currentPullRequestFiles = await getPullRequestFiles(repositorySlug, current);

    return validateFileSetsAreEqual(originalPullRequestFiles, currentPullRequestFiles);
  }

  /// Validate that each pull request has the same number of files and that the
  /// file names match. This must be the case in order to process the revert.
  bool validateFileSetsAreEqual(
    List<PullRequestFile> revertRequestFileList,
    List<PullRequestFile> originalRequestFileList,
  ) {
    if (revertRequestFileList.length != originalRequestFileList.length) {
      return false;
    }

    final List<String?> revertFileNames = [];
    final List<String?> originalFileNames = [];

    for (PullRequestFile element in revertRequestFileList) {
      revertFileNames.add(element.filename);
    }
    for (PullRequestFile element in originalRequestFileList) {
      originalFileNames.add(element.filename);
    }

    // At this point we know the file lists have the same amount of files but not the same files.
    if (!revertFileNames.toSet().containsAll(originalFileNames) ||
        !originalFileNames.toSet().containsAll(revertFileNames)) {
      return false;
    }

    // At this point all the files are the same so we can iterate over one list to
    // compare changes.
    for (PullRequestFile revertRequestFile in revertRequestFileList) {
      final PullRequestFile originalRequestFile =
          originalRequestFileList.firstWhere((element) => element.filename == revertRequestFile.filename);
      if (revertRequestFile.changesCount != originalRequestFile.changesCount ||
          revertRequestFile.additionsCount != originalRequestFile.deletionsCount ||
          revertRequestFile.deletionsCount != originalRequestFile.additionsCount) {
        return false;
      }
    }

    return true;
  }
}
