package it.integry.integrywmsnative.core.data_store.db.respository_new;

import android.os.Handler;
import android.util.Log;

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

import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Objects;
import java.util.concurrent.ExecutorService;

import javax.inject.Inject;

import io.reactivex.rxjava3.schedulers.Schedulers;
import it.integry.integrywmsnative.core.data_store.db.entity.InventarioRoomDTO;
import it.integry.integrywmsnative.core.data_store.db.respository_new.data_source.InventarioLocalDataSource;
import it.integry.integrywmsnative.core.expansion.RunnableArgs;
import it.integry.integrywmsnative.core.mapper.InventarioMapper;
import it.integry.integrywmsnative.core.model.MtbInvent;
import it.integry.integrywmsnative.core.rest.consumers.InventarioRESTConsumer;
import it.integry.integrywmsnative.core.settings.SettingsManager;
import it.integry.integrywmsnative.core.utility.UtilityLiveData;

public class InventarioRepository extends _BaseRepository<MtbInvent, InventarioRoomDTO, InventarioMapper, InventarioLocalDataSource, InventarioRESTConsumer> {

    private final ExecutorService executorService;

    private final Handler handler;

    private final MutableLiveData<List<InventarioRoomDTO>> internalLiveData = new MutableLiveData<>();

    @Inject
    public InventarioRepository(InventarioLocalDataSource localDataSource,
                                InventarioRESTConsumer remoteDataSource,
                                InventarioMapper dataMapper,
                                Handler handler,
                                ExecutorService executorService) {
        super(dataMapper, localDataSource, remoteDataSource);
        this.handler = handler;
        this.executorService = executorService;
    }


    public LiveData<List<InventarioRoomDTO>> retrieve(Runnable onComplete, RunnableArgs<Exception> onError) {
        localDataSource.makeSynchronousRetrieveAllLive(false)
                .observeOn(Schedulers.io())
                .subscribe(internalLiveData::postValue);

        UtilityLiveData.observeOnce(internalLiveData, inventories -> {
            refresh(onComplete, onError);
        });


        return internalLiveData;
    }


    public void refresh(Runnable onComplete, RunnableArgs<Exception> onError) {
        executorService.execute(() -> {
            try {
                var startRetrieve = new Date();
                var remoteData = remoteDataSource.makeSynchronousRetrieveRequest();
                Log.d("Time INVENTORY RETRIEVE", ((new Date().getTime() - startRetrieve.getTime()) / 1000) + " secs");

                if (remoteData == null) remoteData = new ArrayList<>();

                List<MtbInvent> finalRemoteData = remoteData;

                resolveFetch(finalRemoteData, internalLiveData.getValue(),
                        (remoteItem, localItem) -> Objects.equals(remoteItem.getIdInventario(), localItem.getIdInventario()),
                        (remoteItem, localItem) -> {
                            remoteItem.setRemoteSyncDate(localItem.getRemoteSyncDate());
                            remoteItem.setNew(false);
                        }, () -> handler.post(onComplete), ex -> handler.post(() -> onError.run(ex)),
                        SettingsManager.iDB().isFlagIsInventarioCacheEnabled());


            } catch (Exception e) {
                onError.run(e);
            }
        });
    }

    public void insert(InventarioRoomDTO inventarioDTO, Runnable onComplete, RunnableArgs<Exception> onError) {
        localDataSource.makeInsertRequest(inventarioDTO, localResult -> {
            if (onComplete != null) handler.post(onComplete);
        }, onError);
    }

    public void export(InventarioRoomDTO inventarioDTO, Runnable onComplete, RunnableArgs<Exception> onError) {
        remoteDataSource.makeInsertRequest(dataMapper.mapRoomToRest(inventarioDTO), () -> {
            inventarioDTO.setRemoteSyncDate(new Date());

            localDataSource.makeUpdateRequest(inventarioDTO, (ignored) -> {
                handler.post(onComplete);
            }, onError);
        }, onError);
    }

    public void delete(InventarioRoomDTO inventarioDTO, Runnable onComplete, RunnableArgs<Exception> onError) {
        localDataSource.makeDeleteRequest(inventarioDTO, onComplete, onError);
    }

}
