package org.mercury_im.messenger.android.ui.account.login;

import android.app.Application;

import androidx.lifecycle.AndroidViewModel;
import androidx.lifecycle.LiveData;
import androidx.lifecycle.MutableLiveData;

import org.mercury_im.messenger.R;
import org.mercury_im.messenger.android.MercuryImApplication;
import org.mercury_im.messenger.android.ui.MercuryAndroidViewModel;
import org.mercury_im.messenger.android.util.TextChangedListener;
import org.mercury_im.messenger.core.account.error.PasswordError;
import org.mercury_im.messenger.core.account.error.UsernameError;
import org.mercury_im.messenger.core.util.Optional;
import org.mercury_im.messenger.core.viewmodel.account.LoginViewModel;

import javax.inject.Inject;

import io.reactivex.ObservableTransformer;

public class AndroidLoginViewModel extends AndroidViewModel implements MercuryAndroidViewModel<LoginViewModel> {

    private final MutableLiveData<String> loginUsernameError = new MutableLiveData<>();
    private final MutableLiveData<String> loginPasswordError = new MutableLiveData<>();
    private final MutableLiveData<Boolean> loginButtonEnabled = new MutableLiveData<>(true);
    private final MutableLiveData<Boolean> loginFinished = new MutableLiveData<>(false);

    @Inject
    LoginViewModel commonViewModel;

    @Inject
    public AndroidLoginViewModel(Application application) {
        super(application);
        reset();
    }

    public void reset() {
        MercuryImApplication.getApplication().getAppComponent().inject(this);
        commonViewModel.reset();
        addDisposable(getCommonViewModel().getLoginUsernameError()
                .compose(usernameErrorToErrorMessage)
                .subscribe(e -> loginUsernameError.setValue(e.isPresent() ? e.getItem() : null)));
        addDisposable(getCommonViewModel().getLoginPasswordError()
                .compose(passwordErrorToErrorMessage)
                .subscribe(e -> loginPasswordError.setValue(e.isPresent() ? e.getItem() : null)));
        addDisposable(getCommonViewModel().isLoginPossible()
                .subscribe(loginButtonEnabled::setValue));
        addDisposable(getCommonViewModel().isLoginSuccessful()
                .subscribe(loginFinished::setValue));
    }

    private final ObservableTransformer<Optional<UsernameError>, Optional<String>> usernameErrorToErrorMessage =
            upstream -> upstream.map(optional -> {
                if (!optional.isPresent()){
                    return new Optional<>(null);
                }
                UsernameError error = optional.getItem();
                int resourceId;
                switch (error) {
                    case emptyUsername:
                        resourceId = R.string.error_field_required;
                        break;
                    case invalidUsername:
                        resourceId = R.string.error_invalid_username;
                        break;
                    case unreachableServer:
                        resourceId = R.string.error_unreachable_server;
                        break;
                    default:
                        resourceId = R.string.error_uknown_error;
                }
                return new Optional<>(getApplication().getResources().getString(resourceId));
            });

    private final ObservableTransformer<Optional<PasswordError>, Optional<String>> passwordErrorToErrorMessage =
            upstream -> upstream.map(optional -> {
                if (!optional.isPresent()) {
                    return new Optional<>(null);
                }
                PasswordError error = optional.getItem();
                int resourceId;
                switch (error) {
                    case emptyPassword:
                        resourceId = R.string.error_field_required;
                        break;
                    case incorrectPassword:
                        resourceId = R.string.error_incorrect_password;
                        break;
                    default:
                        resourceId = R.string.error_uknown_error;
                }
                return new Optional<>(getApplication().getResources().getString(resourceId));
            });

    @Override
    protected void onCleared() {
        super.onCleared();
        getCommonViewModel().dispose();
    }

    public void onLoginButtonClicked() {
        getCommonViewModel().login();
    }

    public LiveData<String> getLoginUsernameError() {
        return loginUsernameError;
    }

    public LiveData<String> getLoginPasswordError() {
        return loginPasswordError;
    }

    public LiveData<Boolean> isLoginButtonEnabled() {
        return loginButtonEnabled;
    }

    public LiveData<Boolean> isLoginFinished() {
        return loginFinished;
    }

    @Override
    public LoginViewModel getCommonViewModel() {
        return commonViewModel;
    }

    public TextChangedListener getUsernameTextChangedListener() {
        return usernameTextChangedListener;
    }

    public TextChangedListener getPasswordTextChangedListener() {
        return passwordTextChangedListener;
    }

    private final TextChangedListener usernameTextChangedListener = new TextChangedListener() {
        @Override
        public void onTextChanged(CharSequence s, int start, int before, int count) {
            getCommonViewModel().onLoginUsernameChanged(s.toString());
        }
    };

    private final TextChangedListener passwordTextChangedListener = new TextChangedListener() {
        @Override
        public void onTextChanged(CharSequence s, int start, int before, int count) {
            getCommonViewModel().onLoginPasswordChanged(s.toString());
        }
    };

}
