package de.beyondsoft.ownchat.page.contacts;

import de.beyondsoft.ownchat.R;
import de.beyondsoft.ownchat.data.AppPrefsConstants;
import de.beyondsoft.ownchat.data.api.common.ErrorHandlingResponseConverter;
import de.beyondsoft.ownchat.data.api.services.ChatService;
import de.beyondsoft.ownchat.data.prefs.LongPreference;
import de.beyondsoft.ownchat.data.repository.GroupRealmRepository;
import de.beyondsoft.ownchat.data.repository.UserRealmRepository;
import de.beyondsoft.ownchat.data.repository.specifications.GroupByIdSpecification;
import de.beyondsoft.ownchat.data.repository.specifications.GroupByNameSpecification;
import de.beyondsoft.ownchat.data.repository.specifications.GroupSpecification;
import de.beyondsoft.ownchat.data.repository.specifications.UserByIdSpecification;
import de.beyondsoft.ownchat.model.Group;
import de.beyondsoft.ownchat.model.Message;
import de.beyondsoft.ownchat.page.mvp.MVPAbstractPresenter;
import de.beyondsoft.ownchat.utils.SystemUtils;
import de.beyondsoft.ownchat.utils.rx.RxUtils;

import android.support.annotation.NonNull;
import android.util.Log;

import java.util.ArrayList;

import javax.inject.Inject;
import javax.inject.Named;

import rx.Observable;
import rx.Subscriber;
import rx.Subscription;
import rx.android.schedulers.AndroidSchedulers;
import rx.schedulers.Schedulers;

class ContactsPresenter extends MVPAbstractPresenter<ContactsView> implements ContactsView.Callback {

    @Inject
    ChatService mChatService;

    @Inject
    GroupRealmRepository mGroupRealmRepository;

    @Inject
    UserRealmRepository mUserRealmRepository;

    @Inject
    SystemUtils mSystemUtils;

    @Inject
    @Named(AppPrefsConstants.USER_ID)
    LongPreference mUserIdReference;

    @Inject
    ContactsPresenter() {
    }

    @Override
    protected void afterAttachView(@NonNull ContactsView view) {
        super.afterAttachView(view);
        view.setCallback(this);
        view.showProgress();
    }

    @Override
    protected void beforeDetachView(@NonNull ContactsView view) {
        view.setCallback(null);
        super.beforeDetachView(view);
    }

    @Override
    public void loadGroups() {
        Subscription subscription = mChatService.getGroups()
                .flatMap(new ErrorHandlingResponseConverter<>())
                .flatMap(groupResponse -> {
                    if (groupResponse.response.groups != null) {
                        for (Group group : groupResponse.response.groups) {
                            group.userId = mUserIdReference.get();

                            if (group.lastMessage != null) {
                                group.lastMessage.status = Message.Status.DELIVERED;
                                group.lastMessage.userId = mUserIdReference.get();
                            }

                            mUserRealmRepository.update(group.users, new UserByIdSpecification()).subscribe();
                        }
                    }

                    return Observable.just(groupResponse.response.groups);
                })
                .compose(RxUtils.provideDefaultTransformer())
                .subscribe(this::groupsSuccess, this::groupsError);
        addSubscription(subscription);
    }

    private void groupsError(Throwable throwable) {
        Log.e("REALM_TRANSACTION", "An error occurred. This message was brought to you by ContactsPresenter");
        if (mSystemUtils.isNetworkUnavailable()) {
            getView().showError(R.string.error_no_internet_connection);
            return;
        }

        getView().showError(R.string.error_something_went_wrong);
    }

    private void groupsSuccess(ArrayList<Group> groups) {
        mGroupRealmRepository.update(groups, new GroupByIdSpecification(mUserIdReference.get()))
                .subscribeOn(Schedulers.io())
                .observeOn(AndroidSchedulers.mainThread())
                .subscribe(new Subscriber<Object>() {
                    @Override
                    public void onCompleted() {
                        loadGroupsFromDB();
                    }

                    @Override
                    public void onError(Throwable e) {
                        Log.e(ContactsPresenter.class.getSimpleName(), e.getMessage(), e);
                    }

                    @Override
                    public void onNext(Object o) {
                        // nop here
                    }
                });
    }

    @Override
    public void loadGroupsFromDB() {
        GroupSpecification groupSpecification = new GroupSpecification(mUserIdReference.get());
        mGroupRealmRepository.queryForAll(groupSpecification)
                .map(ArrayList::new)
                .compose(RxUtils.provideDefaultTransformer())
                .subscribe(this::loadGroupsFromDBSuccessful, this::loadGroupsError);
    }

    @Override
    public void loadGroupsContainingName(String name) {
        GroupByNameSpecification groupByNameSpecification = new GroupByNameSpecification(name, mUserIdReference.get());
        mGroupRealmRepository.queryForAll(groupByNameSpecification)
                .map(ArrayList::new)
                .compose(RxUtils.provideDefaultTransformer())
                .subscribe(this::loadGroupsFromDBSuccessful, this::loadGroupsError);
    }

    private void loadGroupsFromDBSuccessful(ArrayList<Group> groups) {
        if (!isAttached()) {
            return;
        }

        getView().hideProgress();
        getView().setGroups(groups);
    }

    @Override
    public void storeGroupLocally(long groupId, Message message) {
        Group group = new Group();
        group.id = groupId;
        group.lastMessage = message;
        mGroupRealmRepository.updateGroupMessage(group, new GroupByIdSpecification(mUserIdReference.get()))
                .subscribe(new Subscriber<Object>() {
                    @Override
                    public void onCompleted() {
                        loadGroupsFromDB();
                    }

                    @Override
                    public void onError(Throwable e) {

                    }

                    @Override
                    public void onNext(Object o) {

                    }
                });
    }

    private void loadGroupsError(Throwable throwable) {
        Log.e(ContactsPresenter.class.getSimpleName(), throwable.getMessage(), throwable);
    }
}
