library guru_login;

import 'dart:convert';

import 'package:flutter_login_facebook/flutter_login_facebook.dart';
import 'package:google_sign_in/google_sign_in.dart';
import 'package:guru_login/data/account_credentials.dart';
import 'package:guru_login/data/account_model.dart';
import 'package:guru_utils/log/log.dart';
import 'package:guru_utils/auth/auth_credential_manager.dart';
import 'package:sign_in_with_apple/sign_in_with_apple.dart';

class _FacebookAuthCredential extends AuthCredentialDelegate {
  FacebookLogin? _facebook;

  FacebookLogin get facebook => (_facebook ??= FacebookLogin());

  @override
  AuthType get authType => throw UnimplementedError();

  @override
  Future<AuthResult> login() async {
    if (await facebook.isLoggedIn) {
      await facebook.logOut();
    }
    final result = await facebook.logIn(
        permissions: [FacebookPermission.publicProfile, FacebookPermission.email],
        customPermissions: ['gaming_profile', 'gaming_user_picture']);
    Log.d("signInWithFacebook: ${result.status} ${result.accessToken} ${result.error.toString()}");
    switch (result.status) {
      case FacebookLoginStatus.success:
        final FacebookAccessToken accessToken = result.accessToken!;
        Log.d('''
         [Facebook] Logged in!
         
         Token: ${accessToken.token}
         User id: ${accessToken.userId}
         Expires: ${accessToken.expires}
         Permissions: ${accessToken.permissions}
         Declined permissions: ${accessToken.declinedPermissions}
         ''', tag: "facebook_login");
        return AuthResult.success(FacebookCredential(accessToken: accessToken));
      case FacebookLoginStatus.cancel:
        Log.d('Login cancelled by the user.', tag: "facebook_login");
        break;
      case FacebookLoginStatus.error:
        Log.d(
            'Something went wrong with the login process.\n'
            'Here\'s the error Facebook gave us: ${result.error.toString()}',
            tag: "facebook_login");
        break;
      default:
    }
    return AuthResult.error("[${result.status}]");
  }

  @override
  Future logout() async {
    facebook.logOut();
  }

  @override
  Credential deserializeCredential(String data) {
    final map = json.decode(data);
    return FacebookCredential.fromJson(map);
  }
}

class _GoogleAuthCredential extends AuthCredentialDelegate {
  GoogleSignIn? _google;

  GoogleSignIn get google => (_google ??= GoogleSignIn());

  @override
  AuthType get authType => throw UnimplementedError();

  @override
  Future<AuthResult> login() async {
    final googleAccount = await google.signIn();

    if (googleAccount != null) {
      final googleCredential = await GoogleCredential.build(googleAccount);
      Log.d('''
         [Google] Logged in!         
         IdToken: ${googleCredential.idToken}
         AccessToken: ${googleCredential.accessToken}
         ServerAuthCode: ${googleCredential.serverAuthCode}
         User id: ${googleCredential.uid}
         Name: ${googleCredential.name}
         Email: ${googleCredential.email}
         ''', tag: "google_login");
      return AuthResult.success(googleCredential);
    }
    return AuthResult.error("Google login failed");
  }

  @override
  Future logout() async {
    google.signOut();
  }

  @override
  Credential deserializeCredential(String data) {
    final map = json.decode(data);
    return GoogleCredential.fromJson(map);
  }
}

class _AppleAuthCredential extends AuthCredentialDelegate {
  @override
  AuthType get authType => throw UnimplementedError();

  @override
  Future<AuthResult> login() async {
    final credential = await SignInWithApple.getAppleIDCredential(
      scopes: [
        AppleIDAuthorizationScopes.email,
        AppleIDAuthorizationScopes.fullName,
      ],
    );
    Log.d("credential: ${credential.authorizationCode}");
    Log.d(credential.toString());

    final appleCredential = await AppleCredential.build(credential);
    Log.d('''
         [Apple] Logged in!                  
         UserIdentifier: ${appleCredential.userIdentifier}
         GivenName: ${appleCredential.givenName}
         FamilyName: ${appleCredential.familyName}
         AuthorizationCode: ${appleCredential.authorizationCode}
         IdentityToken: ${appleCredential.identityToken}
         Email: ${appleCredential.email}
         State: ${appleCredential.state}
         ''', tag: "apple_login");
    return AuthResult.success(appleCredential);
  }

  @override
  Future logout() async {}

  @override
  Credential deserializeCredential(String data) {
    final map = json.decode(data);
    return AppleCredential.fromJson(map);
  }
}

class GuruLogin {
  static List<AuthCredentialDelegate> supportedAuthCredentialDelegates = [
    _FacebookAuthCredential(),
    _GoogleAuthCredential(),
    _AppleAuthCredential(),
  ];
}
