import 'package:comunic/helpers/account_credentials_helper.dart';
import 'package:comunic/helpers/api_helper.dart';
import 'package:comunic/models/api_request.dart';
import 'package:comunic/models/authentication_details.dart';
import 'package:comunic/models/login_tokens.dart';
import 'package:shared_preferences/shared_preferences.dart';

/// Account helper
///
/// @author Pierre HUBERT

enum AuthResult {
  SUCCESS,
  TOO_MANY_ATTEMPTS,
  NETWORK_ERROR,
  INVALID_CREDENTIALS
}

class AccountHelper {
  static const _USER_ID_PREFERENCE_NAME = "user_id";

  // Current user ID
  static int _currentUserID = -1;

  /// Checkout whether current user is signed in or not
  ///
  /// Warning : This method MUST BE CALLED AT LEAST ONCE AFTER APP START !!!
  Future<bool> signedIn() async {
    bool signedIn = await AccountCredentialsHelper().get() != null;

    // Load current user ID for later use
    if (signedIn && _currentUserID == -1) await _loadCurrentUserID();

    return signedIn;
  }

  /// Sign in user
  Future<AuthResult> signIn(AuthenticationDetails auth) async {
    final request = APIRequest(uri: "account/login");
    request.addString("userMail", auth.email);
    request.addString("userPassword", auth.password);

    final response = await APIHelper().exec(request);

    // Handle errors
    if (response.code == 401)
      return AuthResult.INVALID_CREDENTIALS;
    else if (response.code == 429)
      return AuthResult.TOO_MANY_ATTEMPTS;
    else if (response.code != 200) return AuthResult.NETWORK_ERROR;

    // Save login tokens
    final tokensObj = response.getObject()["tokens"];
    await AccountCredentialsHelper()
        .set(LoginTokens(tokensObj["token1"], tokensObj["token2"]));

    // Get current user ID
    final userID = await _downloadCurrentUserID();
    if (userID == null) {
      await signOut(); // We can not stay signed in without current user ID
      return AuthResult.NETWORK_ERROR;
    }

    // Save current user ID
    final preferences = await SharedPreferences.getInstance();
    await preferences.setInt(_USER_ID_PREFERENCE_NAME, userID);
    _currentUserID = userID;

    return AuthResult.SUCCESS;
  }

  /// Sign out user
  Future<void> signOut() async {
    await AccountCredentialsHelper().set(null);
    _currentUserID = 0;
  }

  /// Get current user ID from the server
  Future<int> _downloadCurrentUserID() async {
    final response = await APIRequest(
      uri: "user/getCurrentUserID",
      needLogin: true,
    ).exec();

    if (response.code != 200) return null;

    return response.getObject()["userID"];
  }

  /// Get the ID of the currently signed in user
  Future<void> _loadCurrentUserID() async {
    final preferences = await SharedPreferences.getInstance();
    _currentUserID = preferences.getInt(_USER_ID_PREFERENCE_NAME);
  }

  /// Get the ID of the currently signed in user
  static int getCurrentUserID() {
    if (_currentUserID == -1) throw "Current user ID has not been loaded yet!";
    return _currentUserID;
  }
}