package co.smartreceipts.android.identity.widget.login;
import android.content.Context;
import android.support.annotation.NonNull;
import com.google.common.base.Preconditions;
import javax.inject.Inject;
import co.smartreceipts.android.R;
import co.smartreceipts.android.apis.SmartReceiptsApiErrorResponse;
import co.smartreceipts.android.apis.SmartReceiptsApiException;
import co.smartreceipts.android.di.scopes.ApplicationScope;
import co.smartreceipts.android.identity.IdentityManager;
import co.smartreceipts.android.identity.apis.login.LoginType;
import co.smartreceipts.android.identity.apis.login.UserCredentialsPayload;
import co.smartreceipts.android.utils.log.Logger;
import co.smartreceipts.android.widget.model.UiIndicator;
import io.reactivex.Maybe;
import io.reactivex.Observable;
import io.reactivex.android.schedulers.AndroidSchedulers;
import io.reactivex.subjects.ReplaySubject;
import retrofit2.HttpException;
@ApplicationScope
public class LoginInteractor {
private static final int INVALID_CREDENTIALS_CODE = 401;
private static final int ACCOUNT_ALREADY_EXISTS_CODE = 420;
private final Context context;
private final IdentityManager identityManager;
private UserCredentialsPayload userCredentialsPayload;
private ReplaySubject<UiIndicator> uiIndicatorReplaySubject;
@Inject
public LoginInteractor(@NonNull Context context, @NonNull IdentityManager identityManager) {
this.context = Preconditions.checkNotNull(context.getApplicationContext());
this.identityManager = Preconditions.checkNotNull(identityManager);
}
/**
* Initiates a login/sign-up request for a given {@link UserCredentialsPayload}
*
* @param userCredentialsPayload the payload to use to login/sign-up
* @return an {@link Observable}, which will emit {@link UiIndicator} results based on the state
* of the request
*/
@NonNull
public synchronized Observable<UiIndicator> loginOrSignUp(@NonNull final UserCredentialsPayload userCredentialsPayload) {
Logger.info(this, "Initiating user login (or sign up)");
if (this.uiIndicatorReplaySubject == null) {
this.userCredentialsPayload = userCredentialsPayload;
this.uiIndicatorReplaySubject = ReplaySubject.create();
identityManager.logInOrSignUp(userCredentialsPayload)
.map(loginResponse -> UiIndicator.success(getSuccessMessage(userCredentialsPayload)))
.onErrorReturn(throwable -> UiIndicator.error(getErrorMessage(userCredentialsPayload, throwable)))
.startWith(UiIndicator.loading())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(uiIndicatorReplaySubject);
}
return uiIndicatorReplaySubject;
}
/**
* @return the last {@link UserCredentialsPayload} submitted to {@link #loginOrSignUp(UserCredentialsPayload)}
* in a {@link Maybe} observable or {@link Maybe#empty()} if one has either not be made or if
* {@link #onLoginResultsConsumed()} was previously called
*/
@NonNull
public synchronized Maybe<UserCredentialsPayload> getLastUserCredentialsPayload() {
if (userCredentialsPayload != null) {
return Maybe.just(userCredentialsPayload);
} else {
return Maybe.empty();
}
}
/**
* Clears out the results of our previous login request after it has been consumed by the UI
*/
public synchronized void onLoginResultsConsumed() {
userCredentialsPayload = null;
uiIndicatorReplaySubject = null;
}
@NonNull
private String getSuccessMessage(@NonNull final UserCredentialsPayload userCredentialsPayload) {
if (userCredentialsPayload.getLoginType() == LoginType.LogIn) {
return context.getString(R.string.login_success_toast);
} else {
return context.getString(R.string.sign_up_success_toast);
}
}
@NonNull
private String getErrorMessage(@NonNull final UserCredentialsPayload userCredentialsPayload, @NonNull Throwable throwable) {
String errorMessage;
if (userCredentialsPayload.getLoginType() == LoginType.LogIn) {
errorMessage = context.getString(R.string.login_failure_toast);
} else {
errorMessage = context.getString(R.string.sign_up_failure_toast);
}
if (throwable instanceof SmartReceiptsApiException) {
final SmartReceiptsApiException smartReceiptsApiException = (SmartReceiptsApiException) throwable;
final SmartReceiptsApiErrorResponse errorResponse = smartReceiptsApiException.getErrorResponse();
if (errorResponse != null && errorResponse.getErrors() != null && !errorResponse.getErrors().isEmpty()) {
errorMessage = errorResponse.getErrors().get(0);
}
} else if (throwable instanceof HttpException) {
final HttpException httpException = (HttpException) throwable;
if (httpException.code() == INVALID_CREDENTIALS_CODE) {
errorMessage = context.getString(R.string.login_failure_credentials_toast);
}
else if (httpException.code() == ACCOUNT_ALREADY_EXISTS_CODE) {
errorMessage = context.getString(R.string.sign_up_failure_account_exists_toast);
}
}
return errorMessage;
}
}