// 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 'dart:async';
import 'dart:html' as html;

import 'package:flutter/services.dart';
import 'package:flutter_web_plugins/flutter_web_plugins.dart';
import 'package:google_sign_in_platform_interface/google_sign_in_platform_interface.dart';
import 'package:js/js.dart';
import 'package:meta/meta.dart';

import 'src/generated/gapiauth2.dart' as auth2;
import 'src/load_gapi.dart' as gapi;
import 'src/utils.dart' show gapiUserToPluginUserData;

const String _kClientIdMetaSelector = 'meta[name=google-signin-client_id]';
const String _kClientIdAttributeName = 'content';

/// This is only exposed for testing. It shouldn't be accessed by users of the
/// plugin as it could break at any point.
@visibleForTesting
String gapiUrl = 'https://apis.google.com/js/platform.js';

/// Implementation of the google_sign_in plugin for Web.
class GoogleSignInPlugin extends GoogleSignInPlatform {
  /// Constructs the plugin immediately and begins initializing it in the
  /// background.
  ///
  /// The plugin is completely initialized when [initialized] completed.
  GoogleSignInPlugin() {
    _autoDetectedClientId = html
        .querySelector(_kClientIdMetaSelector)
        ?.getAttribute(_kClientIdAttributeName);

    _isGapiInitialized = gapi.inject(gapiUrl).then((_) => gapi.init());
  }

  late Future<void> _isGapiInitialized;
  late Future<void> _isAuthInitialized;
  bool _isInitCalled = false;

  // This method throws if init hasn't been called at some point in the past.
  // It is used by the [initialized] getter to ensure that users can't await
  // on a Future that will never resolve.
  void _assertIsInitCalled() {
    if (!_isInitCalled) {
      throw StateError(
          'GoogleSignInPlugin::init() must be called before any other method in this plugin.');
    }
  }

  /// A future that resolves when both GAPI and Auth2 have been correctly initialized.
  @visibleForTesting
  Future<void> get initialized {
    _assertIsInitCalled();
    return Future.wait([_isGapiInitialized, _isAuthInitialized]);
  }

  String? _autoDetectedClientId;

  /// Factory method that initializes the plugin with [GoogleSignInPlatform].
  static void registerWith(Registrar registrar) {
    GoogleSignInPlatform.instance = GoogleSignInPlugin();
  }

  @override
  Future<void> init({
    List<String> scopes = const <String>[],
    SignInOption signInOption = SignInOption.standard,
    String? hostedDomain,
    String? clientId,
  }) async {
    final String? appClientId = clientId ?? _autoDetectedClientId;
    assert(
        appClientId != null,
        'ClientID not set. Either set it on a '
        '<meta name="google-signin-client_id" content="CLIENT_ID" /> tag,'
        ' or pass clientId when calling init()');

    assert(
        !scopes.any((String scope) => scope.contains(' ')),
        'OAuth 2.0 Scopes for Google APIs can\'t contain spaces.'
        'Check https://developers.google.com/identity/protocols/googlescopes '
        'for a list of valid OAuth 2.0 scopes.');

    await _isGapiInitialized;

    final auth2.GoogleAuth auth = auth2.init(auth2.ClientConfig(
      hosted_domain: hostedDomain,
      // The js lib wants a space-separated list of values
      scope: scopes.join(' '),
      client_id: appClientId!,
    ));

    Completer<void> isAuthInitialized = Completer<void>();
    _isAuthInitialized = isAuthInitialized.future;
    _isInitCalled = true;

    auth.then(allowInterop((auth2.GoogleAuth initializedAuth) {
      // onSuccess

      // TODO: https://github.com/flutter/flutter/issues/48528
      // This plugin doesn't notify the app of external changes to the
      // state of the authentication, i.e: if you logout elsewhere...

      isAuthInitialized.complete();
    }), allowInterop((auth2.GoogleAuthInitFailureError reason) {
      // onError
      isAuthInitialized.completeError(PlatformException(
        code: reason.error,
        message: reason.details,
        details:
            'https://developers.google.com/identity/sign-in/web/reference#error_codes',
      ));
    }));

    return _isAuthInitialized;
  }

  @override
  Future<GoogleSignInUserData?> signInSilently() async {
    await initialized;

    return gapiUserToPluginUserData(
        await auth2.getAuthInstance()?.currentUser?.get());
  }

  @override
  Future<GoogleSignInUserData?> signIn() async {
    await initialized;
    try {
      return gapiUserToPluginUserData(await auth2.getAuthInstance()?.signIn());
    } on auth2.GoogleAuthSignInError catch (reason) {
      throw PlatformException(
        code: reason.error,
        message: 'Exception raised from GoogleAuth.signIn()',
        details:
            'https://developers.google.com/identity/sign-in/web/reference#error_codes_2',
      );
    }
  }

  @override
  Future<GoogleSignInTokenData> getTokens(
      {required String email, bool? shouldRecoverAuth}) async {
    await initialized;

    final auth2.GoogleUser? currentUser =
        auth2.getAuthInstance()?.currentUser?.get();
    final auth2.AuthResponse? response = currentUser?.getAuthResponse();

    return GoogleSignInTokenData(
        idToken: response?.id_token, accessToken: response?.access_token);
  }

  @override
  Future<void> signOut() async {
    await initialized;

    return auth2.getAuthInstance()?.signOut();
  }

  @override
  Future<void> disconnect() async {
    await initialized;

    final auth2.GoogleUser? currentUser =
        auth2.getAuthInstance()?.currentUser?.get();

    if (currentUser == null) return;

    return currentUser.disconnect();
  }

  @override
  Future<bool> isSignedIn() async {
    await initialized;

    final auth2.GoogleUser? currentUser =
        auth2.getAuthInstance()?.currentUser?.get();

    if (currentUser == null) return false;

    return currentUser.isSignedIn();
  }

  @override
  Future<void> clearAuthCache({required String token}) async {
    await initialized;

    return auth2.getAuthInstance()?.disconnect();
  }

  @override
  Future<bool> requestScopes(List<String> scopes) async {
    await initialized;

    final currentUser = auth2.getAuthInstance()?.currentUser?.get();

    if (currentUser == null) return false;

    final grantedScopes = currentUser.getGrantedScopes() ?? '';
    final missingScopes =
        scopes.where((scope) => !grantedScopes.contains(scope));

    if (missingScopes.isEmpty) return true;

    final response = await currentUser
        .grant(auth2.SigninOptions(scope: missingScopes.join(' ')));

    return response != null;
  }
}
