package com.p3.bewoplaner.page.contacts;

import com.p3.bewoplaner.R;
import com.p3.bewoplaner.data.AppPrefsConstants;
import com.p3.bewoplaner.data.api.common.ErrorHandlingResponseConverter;
import com.p3.bewoplaner.data.api.responses.GroupResponse;
import com.p3.bewoplaner.data.api.services.ChatService;
import com.p3.bewoplaner.data.prefs.LongPreference;
import com.p3.bewoplaner.data.repository.GroupRealmRepository;
import com.p3.bewoplaner.data.repository.UserRealmRepository;
import com.p3.bewoplaner.data.repository.specifications.GroupByIdSpecification;
import com.p3.bewoplaner.data.repository.specifications.GroupByNameSpecification;
import com.p3.bewoplaner.data.repository.specifications.GroupSpecification;
import com.p3.bewoplaner.data.repository.specifications.UserByIdSpecification;
import com.p3.bewoplaner.model.Group;
import com.p3.bewoplaner.model.Message;
import com.p3.bewoplaner.page.mvp.MVPAbstractPresenter;
import com.p3.bewoplaner.utils.SystemUtils;
import com.p3.bewoplaner.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.functions.Func1;
import rx.schedulers.Schedulers;

/**
 * Created by imarneanu on 2/20/17.
 */
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);
    }

    /**
     * Get all user groups from server.
     */

    @Override
    public void loadGroups() {
        Subscription subscription = mChatService.getGroups()
                .flatMap(new ErrorHandlingResponseConverter<>())
                .flatMap(new Func1<GroupResponse, Observable<ArrayList<Group>>>() {
                    @Override
                    public Observable<ArrayList<Group>> call(GroupResponse 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);
    }

    /**
     * Send error messages to view.
     */
    private void groupsError(Throwable throwable) {
        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
                    }
                });
    }

    /**
     * Load groups from local database.
     */

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

    /**
     * Load groups by name.
     */
    @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);
    }
}
