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

import 'dart:math';

import 'package:googleapis/firestore/v1.dart';
import 'package:mockito/mockito.dart';
import 'package:http/http.dart';

import 'package:builder/src/builder.dart';
import 'package:builder/src/commits_cache.dart';
import 'package:builder/src/firestore.dart';
import 'package:builder/src/result.dart';
import 'test_data.dart';

class BuilderTest {
  final client = HttpClientMock();
  final firestore = FirestoreServiceFake();
  late CommitsCache commitsCache;
  late Build builder;
  Map<String, dynamic> firstChange;

  BuilderTest(this.firstChange) {
    commitsCache = CommitsCache(firestore, client);
    builder = Build(BuildInfo.fromResult(firstChange), commitsCache, firestore);
  }

  Future<void> update() async {
    await storeBuildCommitsInfo();
  }

  Future<void> storeBuildCommitsInfo() async {
    await builder.storeBuildCommitsInfo();
    // Test expectations
  }

  Future<void> storeChange(Map<String, dynamic> change) async {
    return builder.storeChange(change);
  }
}

class FirestoreServiceFake extends Fake implements FirestoreService {
  Map<String, Map<String, dynamic>> commits = Map.from(fakeFirestoreCommits);
  Map<String, Map<String, dynamic>> results = Map.from(fakeFirestoreResults);
  List<Map<String, dynamic>> fakeTryResults =
      List.from(fakeFirestoreTryResults);
  int addedResultIdCounter = 1;

  @override
  Future<bool> isStaging() async => false;

  @override
  Future<Commit?> getCommit(String hash) async {
    final commit = commits[hash];
    if (commit == null) {
      return null;
    }
    return Commit.fromJson(hash, commits[hash]!);
  }

  @override
  Future<Commit> getCommitByIndex(int? index) {
    for (final entry in commits.entries) {
      if (entry.value[fIndex] == index) {
        return Future.value(Commit.fromJson(entry.key, entry.value));
      }
    }
    throw 'No commit found with index $index';
  }

  @override
  Future<Commit> getLastCommit() => getCommitByIndex(
      commits.values.map<int?>((commit) => commit[fIndex]).reduce(max));

  @override
  Future<void> addCommit(String id, Map<String, dynamic> data) async {
    commits[id] = data..[fHash] = id;
  }

  @override
  Future<String> findResult(
      Map<String, dynamic> change, int startIndex, int endIndex) {
    String? resultId;
    int? resultEndIndex;
    for (final entry in results.entries) {
      final result = entry.value;
      if (result[fName] == change[fName] &&
          result[fResult] == change[fResult] &&
          result[fExpected] == change[fExpected] &&
          result[fPreviousResult] == change[fPreviousResult] &&
          result[fBlamelistEndIndex] >= startIndex &&
          result[fBlamelistStartIndex] <= endIndex) {
        if (resultEndIndex == null ||
            resultEndIndex < result[fBlamelistEndIndex]) {
          resultId = entry.key;
          resultEndIndex = result[fBlamelistEndIndex];
        }
      }
    }
    return Future.value(resultId);
  }

  @override
  Future<List<SafeDocument>> findActiveResults(
      String? name, String? configuration) async {
    return [
      for (final id in results.keys)
        if (results[id]![fName] == name &&
            results[id]![fActiveConfigurations] != null &&
            results[id]![fActiveConfigurations].contains(configuration))
          SafeDocument(Document()
            ..fields = taggedMap(Map.from(results[id]!))
            ..name = id)
    ];
  }

  @override
  Future<Document?> storeResult(Map<String, dynamic> result) async {
    final id = 'resultDocumentID$addedResultIdCounter';
    addedResultIdCounter++;
    results[id] = result;
    return null;
  }

  @override
  Future<bool> updateResult(
      String resultId, String? configuration, int startIndex, int endIndex,
      {required bool failure}) {
    final result = Map<String, dynamic>.from(results[resultId]!);

    result[fBlamelistStartIndex] =
        max<int>(startIndex, result[fBlamelistStartIndex]);

    result[fBlamelistEndIndex] = min<int>(endIndex, result[fBlamelistEndIndex]);
    if (!result[fConfigurations].contains(configuration)) {
      result[fConfigurations] = List<String?>.from(result[fConfigurations])
        ..add(configuration)
        ..sort();
    }
    if (failure) {
      result[fActive] = true;
      if (!result[fActiveConfigurations].contains(configuration)) {
        result[fActiveConfigurations] =
            List<String?>.from(result[fActiveConfigurations])
              ..add(configuration)
              ..sort();
      }
    }
    results[resultId] = result;
    return Future.value(result[fApproved] ?? false);
  }

  @override
  Future<void> removeActiveConfiguration(
      SafeDocument activeResult, String? configuration) async {
    final result = Map<String, dynamic>.from(results[activeResult.name]!);
    result[fActiveConfigurations] = List.from(result[fActiveConfigurations])
      ..remove(configuration);
    if (result[fActiveConfigurations].isEmpty) {
      result.remove(fActiveConfigurations);
      result.remove(fActive);
    }
    results[activeResult.name] = result;
  }

  @override
  Future<List<Map<String, Value>>> findRevertedChanges(int index) async {
    return results.values
        .where((change) =>
            change[fPinnedIndex] == index ||
            (change[fBlamelistStartIndex] == index &&
                change[fBlamelistEndIndex] == index))
        .map(taggedMap)
        .toList();
  }

  @override
  Future<List<SafeDocument>> tryApprovals(int review) async {
    return fakeTryResults
        .where(
            (result) => result[fReview] == review && result[fApproved] == true)
        .map(taggedMap)
        .map((fields) => SafeDocument(Document()
          ..fields = fields
          ..name = ''))
        .toList();
  }

  @override
  Future<List<SafeDocument>> tryResults(
      int review, String configuration) async {
    return fakeTryResults
        .where((result) =>
            result[fReview] == review &&
            result[fConfigurations].contains(configuration))
        .map(taggedMap)
        .map((fields) => SafeDocument(Document()
          ..fields = fields
          ..name = ''))
        .toList();
  }

  @override
  Future<bool> reviewIsLanded(int review) =>
      Future.value(commits.values.any((commit) => commit[fReview] == review));
}

class HttpClientMock extends Mock implements BaseClient {}

class ResponseFake extends Fake implements Response {
  @override
  String body;
  ResponseFake(this.body);
}
