import 'package:aitrainer_app/model/cache.dart';
import 'package:aitrainer_app/model/user.dart';
import 'package:aitrainer_app/service/customer_service.dart';
import 'package:aitrainer_app/service/firebase_api.dart';
import 'package:aitrainer_app/service/logging.dart';
import 'package:aitrainer_app/util/not_found_exception.dart';
import 'package:firebase_auth/firebase_auth.dart' as auth;

class UserRepository with Logging {
  late User user;

  UserRepository() {
    this.createNewUser();
  }

  setEmail(String email) {
    this.user.email = email;
  }

  setPassword(String password) {
    this.user.password = password;
  }

  createNewUser() {
    this.user = User();
  }

  Future<void> addUser() async {
    final User modelUser = this.user;
    try {
      String rc = await FirebaseApi().registerEmail(modelUser.email!, modelUser.password!);
      if (rc == FirebaseApi.SIGN_IN_OK) {
        modelUser.firebaseUid = Cache().firebaseUid;
        await CustomerApi().addUser(modelUser);
      }
    } catch (e) {
      log(e.toString());
      throw new Exception(e);
    }
  }

  Future<void> addUserFB() async {
    final User modelUser = this.user;
    try {
      Map<String, dynamic> userData = await FirebaseApi().registerWithFacebook();

      modelUser.email = userData['email'];
      if (modelUser.email == null) {
        throw new Exception("Facebook signup was not successful. Please try another method");
      }
      modelUser.password = Cache().firebaseUid;
      modelUser.firebaseUid = Cache().firebaseUid;
      await CustomerApi().addUser(modelUser);
    } on auth.FirebaseAuthException catch (e) {
      if (e.code == 'email-already-in-use') {
        log('The account already exists for that email.');
        throw Exception("The email address has been registered already");
      } else if (e.code == 'weak-password') {
        log('The password provided is too weak.');
        throw Exception("Password too short");
      } else if (e.code == 'account-exists-with-different-credential') {
        log(e.code);
        throw Exception("The account exists with different credential");
      } else {
        print(e.code);
        throw Exception(e);
      }
    } on WorkoutTestException catch (ex) {
      if (ex.code == WorkoutTestException.CUSTOMER_EXISTS) {
        log('The account already exists for that email.');
        throw Exception("The email address has been registered already");
      }
    } on Exception catch (ex) {
      log("FB exception: " + ex.toString());
      throw Exception("Facebook Sign In failed");
    }
  }

  Future<void> addUserGoogle() async {
    final User modelUser = this.user;
    try {
      Map<String, dynamic> userData = await FirebaseApi().registerWithGoogle();

      modelUser.email = userData['email'];
      if (modelUser.email == null) {
        throw new Exception("Google signup was not successful. Please try another method");
      }
      modelUser.password = Cache().firebaseUid;
      modelUser.firebaseUid = Cache().firebaseUid;
      await CustomerApi().addUser(modelUser);
    } on auth.FirebaseAuthException catch (e) {
      if (e.code == 'email-already-in-use') {
        log('The account already exists for that email.');
        throw Exception("The email address has been registered already");
      } else {
        throw Exception(e);
      }
    } on WorkoutTestException catch (ex) {
      if (ex.code == WorkoutTestException.CUSTOMER_EXISTS) {
        log('The account already exists for that email.');
        throw Exception("The email address has been registered already");
      }
    } on Exception catch (ex) {
      log("Google exception: " + ex.toString());
      throw Exception("Google Sign In failed");
    }
  }

  Future<void> addUserApple() async {
    final User modelUser = this.user;
    try {
      Map<String, dynamic> userData = await FirebaseApi().registerWithApple();

      modelUser.email = userData['email'];
      if (modelUser.email == null) {
        throw new Exception("Apple signup was not successful. Please try another method");
      }
      modelUser.password = Cache().firebaseUid;
      modelUser.firebaseUid = Cache().firebaseUid;
      await CustomerApi().addUser(modelUser);
    } on auth.FirebaseAuthException catch (e) {
      if (e.code == 'email-already-in-use') {
        log('The account already exists for that email.');
        throw Exception("The email address has been registered already");
      }
    } on WorkoutTestException catch (ex) {
      if (ex.code == WorkoutTestException.CUSTOMER_EXISTS) {
        log('The account already exists for that email.');
        throw Exception("The email address has been registered already");
      }
    } on Exception catch (ex) {
      log("Apple exception: " + ex.toString());
      throw Exception(ex);
    }
  }

  Future<void> getUserByFB() async {
    final User modelUser = this.user;
    try {
      Map<String, dynamic> userData = await FirebaseApi().signInWithFacebook();
      modelUser.email = userData['email'];

      await CustomerApi().getUserByEmail(modelUser.email!);
      await Cache().afterFirebaseLogin();
    } /* on FacebookAuthException catch (e) {
      switch (e.errorCode) {
        case FacebookAuthErrorCode.OPERATION_IN_PROGRESS:
          throw Exception("You have a previous Facebook login operation in progress");
          break;
        case FacebookAuthErrorCode.CANCELLED:
          throw Exception("Facebook login cancelled");
          break;
        case FacebookAuthErrorCode.FAILED:
          throw Exception("Facebook login failed");
          break;
      }
    } */
    on NotFoundException catch (ex) {
      log("FB exception: " + ex.toString());
      throw Exception("Customer does not exist or the password is wrong");
    } on Exception catch (e) {
      log(e.toString());
      throw new Exception(e);
    }
  }

  Future<void> getUserByGoogle() async {
    final User modelUser = this.user;
    try {
      Map<String, dynamic> userData = await FirebaseApi().signInWithGoogle();
      if (userData['email'] == null) {
        throw new Exception("Google login was not successful");
      }
      modelUser.email = userData['email'];

      await CustomerApi().getUserByEmail(modelUser.email!);
      await Cache().afterFirebaseLogin();
    } on Exception catch (ex) {
      log("Google exception: " + ex.toString());
      throw Exception(ex);
    }
  }

  Future<void> getUserByApple() async {
    final User modelUser = this.user;
    Map<String, dynamic> userData = await FirebaseApi().signInWithApple();
    if (userData['email'] == null) {
      throw new Exception("Apple login was not successful");
    }
    modelUser.email = userData['email'];
    try {
      await CustomerApi().getUserByEmail(modelUser.email!);
      await Cache().afterFirebaseLogin();
    } on Exception catch (ex) {
      log("Apple exception: " + ex.toString());
      throw Exception("Customer does not exist or the password is wrong");
    }
  }

  Future<void> getUser() async {
    final User modelUser = this.user;
    String rc = await FirebaseApi().signInEmail(modelUser.email, modelUser.password);

    if (rc == FirebaseApi.SIGN_IN_OK) {
      await CustomerApi().getUserByEmail(modelUser.email!);
      await Cache().afterFirebaseLogin();
    } else {
      log("Exception: user not found or password is wrong");
      throw Exception("Customer does not exist or the password is wrong");
    }
  }

  Future<void> resetPassword() async {
    final User modelUser = this.user;
    await FirebaseApi().resetPassword(modelUser.email!);
  }
}
