package it.integry.integrywmsnative.gest.prod_versamento_materiale;

import androidx.lifecycle.MutableLiveData;

import org.jetbrains.annotations.NotNull;

import java.util.Iterator;
import java.util.List;

import javax.inject.Inject;

import it.integry.integrywmsnative.core.interfaces.viewmodel_listeners.ILoadingListener;
import it.integry.integrywmsnative.core.model.MtbAart;
import it.integry.integrywmsnative.core.model.MtbColr;
import it.integry.integrywmsnative.core.model.MtbColt;
import it.integry.integrywmsnative.core.model.MtbDepoPosizione;
import it.integry.integrywmsnative.core.rest.consumers.ColliMagazzinoRESTConsumer;
import it.integry.integrywmsnative.core.rest.consumers.MesRESTConsumer;
import it.integry.integrywmsnative.core.utility.UtilityBigDecimal;
import it.integry.integrywmsnative.core.utility.UtilityString;
import it.integry.integrywmsnative.gest.prod_versamento_materiale.dto.OrdineLavorazioneDTO;

public class ProdVersamentoMaterialeViewModel {

    private final ColliMagazzinoRESTConsumer mColliMagazzinoRESTConsumer;
    private final MesRESTConsumer mMesRESTConsumer;

    private boolean mFlagVersamentoDirettoProduzione;

    private final MutableLiveData<MtbColt> mtbColtMutableLiveData = new MutableLiveData<>();
    private final MutableLiveData<MtbColr> mtbColrMutableLiveData = new MutableLiveData<>();
    private final MutableLiveData<List<OrdineLavorazioneDTO>> openedOrderLavMutableLiveList = new MutableLiveData<>();
    private final MutableLiveData<MtbDepoPosizione> mtbDepoPosizioneMutableLiveData = new MutableLiveData<>();

    private Listener mListener;

    @Inject
    public ProdVersamentoMaterialeViewModel(ColliMagazzinoRESTConsumer colliMagazzinoRESTConsumer, MesRESTConsumer mesRESTConsumer) {
        this.mColliMagazzinoRESTConsumer = colliMagazzinoRESTConsumer;
        this.mMesRESTConsumer = mesRESTConsumer;
    }


    public void init(boolean flagVersamentoDirettoProduzione) {
        this.mFlagVersamentoDirettoProduzione = flagVersamentoDirettoProduzione;
    }


    public void setMtbColt(MtbColt mtbColt) {
        this.mtbColtMutableLiveData.setValue(mtbColt);
    }


    public void setPosizione(MtbDepoPosizione mtbDepoPosizione) {
        this.mtbDepoPosizioneMutableLiveData.postValue(mtbDepoPosizione);
        MtbColt mtbColt = mtbColtMutableLiveData.getValue();

        this.sendOnLoadingStarted();

        if (mtbDepoPosizione != null && mtbDepoPosizione.isFlagLineaProduzione() && mtbColt != null) {
            if (!mFlagVersamentoDirettoProduzione) {
                createColloScarico(mtbDepoPosizione);
            } else {
                if (mtbColt.getMtbColr() == null || mtbColt.getMtbColr().size() <= 0) {
                    this.sendWarning("Il collo selezionato non presenta articoli versabili sulla linea.", this::sendRequestLUOpen);
                    return;
                } else if (mtbColt.getMtbColr().size() > 1) {
                    this.sendWarning("Il collo selezionato contiene più articoli, solo il primo verrà versato in questa sessione. <br> Per versare i colli restanti ripetere l'operazione di versamento.",
                            () -> {
                                cyclicGetOrdiniLavByCollo(mtbColt.getMtbColr().iterator(), mtbDepoPosizione);
                            });
                    return;

                }

                mMesRESTConsumer.getOrdiniLavorazioneMateriale(
                        mtbDepoPosizione.getPosizione(),
                        getIdMaterialeFromCollo(mtbColt),
                        ordini -> {
                            if(ordini == null || ordini.isEmpty())
                                this.sendError(new Exception("Nessun ordine compatibile con " + getIdMaterialeFromCollo(mtbColt) + " sulla linea " + mtbDepoPosizione.getPosizione()), true);
                            else {
                                setCurrentOrders(ordini, mtbColt.getMtbColr().get(0));
                                this.sendOnLoadingEnded();
                            }

                        },
                        e -> this.sendWarning(e.getMessage(), this::sendRequestLUOpen));
            }
        } else {
            this.sendWarning("Si è verificato un errore. Riprovare", this::sendRequestLUOpen);
        }
    }

    private void createColloScarico(MtbDepoPosizione mtbDepoPosizione) {

        this.sendOnLoadingStarted();

        this.mColliMagazzinoRESTConsumer.createColloScaricoDaCarico(mtbColtMutableLiveData.getValue(), mtbDepoPosizione,
                generatedMtbColt -> {
                    this.sendOnLoadingEnded();
                    this.sendOnDataSaved();
                }, this::sendError);
    }



    private String getIdMaterialeFromCollo(MtbColt mtbColt) {
        MtbAart articolo = mtbColt.getMtbColr().get(0).getMtbAart();
        return UtilityString.isNullOrEmpty(articolo.getIdArtEqui()) ? articolo.getCodMart() : articolo.getIdArtEqui();
    }

    private void setCurrentOrders(List<OrdineLavorazioneDTO> ordini, MtbColr currentMtbColr) {
        currentMtbColr.setQtaCnf(UtilityBigDecimal.divide(currentMtbColr.getQtaCol(), currentMtbColr.getNumCnf()));
        this.mtbColrMutableLiveData.setValue(currentMtbColr);
        this.openedOrderLavMutableLiveList.setValue(ordini);
    }


    private void cyclicGetOrdiniLavByCollo(@NotNull Iterator<MtbColr> mtbColrIterator, MtbDepoPosizione mtbDepoPosizione) {
        MtbColr currentMtbColr = mtbColrIterator.next();
        MtbAart currentMtbAart = currentMtbColr.getMtbAart();

        this.mMesRESTConsumer.getOrdiniLavorazioneMateriale(
                mtbDepoPosizione.getPosizione(),
                UtilityString.isNullOrEmpty(currentMtbAart.getIdArtEqui()) ? currentMtbAart.getCodMart() : currentMtbAart.getIdArtEqui(),
                ordini -> {
                    if (ordini == null || ordini.isEmpty()) {
                        if (mtbColrIterator.hasNext()) {
                            cyclicGetOrdiniLavByCollo(mtbColrIterator, mtbDepoPosizione);
                        } else {
                            setCurrentOrders(ordini, currentMtbColr);
                        }
                    } else {
                        setCurrentOrders(ordini, currentMtbColr);
                    }
                }
                , e -> this.sendWarning(e.getMessage(), this::sendRequestLUOpen));
    }



    public void save(List<OrdineLavorazioneDTO> selectedOrders) {
        this.sendOnLoadingStarted();

        this.mColliMagazzinoRESTConsumer.createColliScaricoDaOrdineLavorazione(
                this.mtbColtMutableLiveData.getValue(),
                this.mtbColrMutableLiveData.getValue(),
                this.mtbDepoPosizioneMutableLiveData.getValue(),
                selectedOrders,
                mtbColtSaved -> {
                    this.sendOnDataSaved();
                }, this::sendError);
    }












    public MutableLiveData<MtbColt> getMtbColtMutableLiveData() {
        return mtbColtMutableLiveData;
    }

    public MutableLiveData<MtbColr> getMtbColrMutableLiveData() {
        return mtbColrMutableLiveData;
    }

    public MutableLiveData<List<OrdineLavorazioneDTO>> getOpenedOrderLavMutableLiveList() {
        return openedOrderLavMutableLiveList;
    }


    public ProdVersamentoMaterialeViewModel setListener(Listener listener) {
        this.mListener = listener;
        return this;
    }

    private void sendRequestLUOpen() {
        if (this.mListener != null) mListener.requestLUOpen();
    }

    private void sendOnLoadingStarted() {
        if (this.mListener != null) mListener.onLoadingStarted();
    }

    private void sendOnLoadingEnded() {
        if (this.mListener != null) mListener.onLoadingEnded();
    }

    private void sendWarning(String warningText, Runnable action) {
        if (this.mListener != null) mListener.onWarning(warningText, action);
    }

    private void sendError(Exception ex) {
        if (this.mListener != null) mListener.onError(ex, false);
    }

    private void sendError(Exception ex, boolean requestClose) {
        if (this.mListener != null) mListener.onError(ex, requestClose);
    }

    private void sendOnDataSaved() {
        if (this.mListener != null) mListener.onDataSaved();
    }

    public interface Listener extends ILoadingListener {

        void requestLUOpen();

        void onError(Exception ex, boolean requestClose);

        void onWarning(String warningText, Runnable action);

        void onDataSaved();
    }

}
