// Copyright 2013 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 'package:flutter/services.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:google_sign_in_android/google_sign_in_android.dart';
import 'package:google_sign_in_android/src/utils.dart';
import 'package:google_sign_in_platform_interface/google_sign_in_platform_interface.dart';

const Map<String, String> kUserData = <String, String>{
  'email': 'john.doe@gmail.com',
  'id': '8162538176523816253123',
  'photoUrl': 'https://lh5.googleusercontent.com/photo.jpg',
  'displayName': 'John Doe',
  'idToken': '123',
  'serverAuthCode': '789',
};

const Map<dynamic, dynamic> kTokenData = <String, dynamic>{
  'idToken': '123',
  'accessToken': '456',
  'serverAuthCode': '789',
};

const Map<String, dynamic> kDefaultResponses = <String, dynamic>{
  'init': null,
  'signInSilently': kUserData,
  'signIn': kUserData,
  'signOut': null,
  'disconnect': null,
  'isSignedIn': true,
  'getTokens': kTokenData,
  'requestScopes': true,
};

final GoogleSignInUserData? kUser = getUserDataFromMap(kUserData);
final GoogleSignInTokenData kToken =
    getTokenDataFromMap(kTokenData as Map<String, dynamic>);

void main() {
  TestWidgetsFlutterBinding.ensureInitialized();

  final GoogleSignInAndroid googleSignIn = GoogleSignInAndroid();
  final MethodChannel channel = googleSignIn.channel;

  final List<MethodCall> log = <MethodCall>[];
  late Map<String, dynamic>
      responses; // Some tests mutate some kDefaultResponses

  setUp(() {
    responses = Map<String, dynamic>.from(kDefaultResponses);
    _ambiguate(TestDefaultBinaryMessengerBinding.instance)!
        .defaultBinaryMessenger
        .setMockMethodCallHandler(
      channel,
      (MethodCall methodCall) {
        log.add(methodCall);
        final dynamic response = responses[methodCall.method];
        if (response != null && response is Exception) {
          return Future<dynamic>.error('$response');
        }
        return Future<dynamic>.value(response);
      },
    );
    log.clear();
  });

  test('registered instance', () {
    GoogleSignInAndroid.registerWith();
    expect(GoogleSignInPlatform.instance, isA<GoogleSignInAndroid>());
  });

  test('signInSilently transforms platform data to GoogleSignInUserData',
      () async {
    final dynamic response = await googleSignIn.signInSilently();
    expect(response, kUser);
  });
  test('signInSilently Exceptions -> throws', () async {
    responses['signInSilently'] = Exception('Not a user');
    expect(googleSignIn.signInSilently(),
        throwsA(isInstanceOf<PlatformException>()));
  });

  test('signIn transforms platform data to GoogleSignInUserData', () async {
    final dynamic response = await googleSignIn.signIn();
    expect(response, kUser);
  });
  test('signIn Exceptions -> throws', () async {
    responses['signIn'] = Exception('Not a user');
    expect(googleSignIn.signIn(), throwsA(isInstanceOf<PlatformException>()));
  });

  test('getTokens transforms platform data to GoogleSignInTokenData', () async {
    final dynamic response = await googleSignIn.getTokens(
        email: 'example@example.com', shouldRecoverAuth: false);
    expect(response, kToken);
    expect(
        log[0],
        isMethodCall('getTokens', arguments: <String, dynamic>{
          'email': 'example@example.com',
          'shouldRecoverAuth': false,
        }));
  });

  test('Other functions pass through arguments to the channel', () async {
    final Map<void Function(), Matcher> tests = <void Function(), Matcher>{
      () {
        googleSignIn.init(
            hostedDomain: 'example.com',
            scopes: <String>['two', 'scopes'],
            signInOption: SignInOption.games,
            clientId: 'fakeClientId');
      }: isMethodCall('init', arguments: <String, dynamic>{
        'hostedDomain': 'example.com',
        'scopes': <String>['two', 'scopes'],
        'signInOption': 'SignInOption.games',
        'clientId': 'fakeClientId',
        'serverClientId': null,
        'forceCodeForRefreshToken': false,
      }),
      () {
        googleSignIn.initWithParams(const SignInInitParameters(
            hostedDomain: 'example.com',
            scopes: <String>['two', 'scopes'],
            signInOption: SignInOption.games,
            clientId: 'fakeClientId',
            serverClientId: 'fakeServerClientId',
            forceCodeForRefreshToken: true));
      }: isMethodCall('init', arguments: <String, dynamic>{
        'hostedDomain': 'example.com',
        'scopes': <String>['two', 'scopes'],
        'signInOption': 'SignInOption.games',
        'clientId': 'fakeClientId',
        'serverClientId': 'fakeServerClientId',
        'forceCodeForRefreshToken': true,
      }),
      () {
        googleSignIn.getTokens(
            email: 'example@example.com', shouldRecoverAuth: false);
      }: isMethodCall('getTokens', arguments: <String, dynamic>{
        'email': 'example@example.com',
        'shouldRecoverAuth': false,
      }),
      () {
        googleSignIn.clearAuthCache(token: 'abc');
      }: isMethodCall('clearAuthCache', arguments: <String, dynamic>{
        'token': 'abc',
      }),
      () {
        googleSignIn.requestScopes(<String>['newScope', 'anotherScope']);
      }: isMethodCall('requestScopes', arguments: <String, dynamic>{
        'scopes': <String>['newScope', 'anotherScope'],
      }),
      googleSignIn.signOut: isMethodCall('signOut', arguments: null),
      googleSignIn.disconnect: isMethodCall('disconnect', arguments: null),
      googleSignIn.isSignedIn: isMethodCall('isSignedIn', arguments: null),
    };

    for (final void Function() f in tests.keys) {
      f();
    }

    expect(log, tests.values);
  });
}

/// This allows a value of type T or T? to be treated as a value of type T?.
///
/// We use this so that APIs that have become non-nullable can still be used
/// with `!` and `?` on the stable branch.
T? _ambiguate<T>(T? value) => value;
