package it.integry.integrywmsnative.view.dialogs.scan_or_create_lu;

import com.annimon.stream.Stream;

import it.integry.barcode_base_android_library.model.BarcodeScanDTO;
import it.integry.integrywmsnative.core.exception.AlreadyAttachedDocumentToLUException;
import it.integry.integrywmsnative.core.exception.NoLUFoundException;
import it.integry.integrywmsnative.core.exception.TooManyLUFoundInMonoLUPositionException;
import it.integry.integrywmsnative.core.expansion.RunnableArgs;
import it.integry.integrywmsnative.core.interfaces.viewmodel_listeners.ILoadingListener;
import it.integry.integrywmsnative.core.model.MtbAart;
import it.integry.integrywmsnative.core.model.MtbColt;
import it.integry.integrywmsnative.core.model.MtbDepoPosizione;
import it.integry.integrywmsnative.core.model.secondary.GestioneEnum;
import it.integry.integrywmsnative.core.rest.consumers.ArticoloRESTConsumer;
import it.integry.integrywmsnative.core.rest.consumers.BarcodeRESTConsumer;
import it.integry.integrywmsnative.core.rest.consumers.ColliMagazzinoRESTConsumer;
import it.integry.integrywmsnative.core.rest.consumers.PosizioniRESTConsumer;
import it.integry.integrywmsnative.core.settings.SettingsManager;
import it.integry.integrywmsnative.core.utility.UtilityBarcode;
import it.integry.integrywmsnative.core.utility.UtilityPosizione;
import it.integry.integrywmsnative.core.utility.UtilityString;

public class DialogScanOrCreateLUViewModel {


    private final PosizioniRESTConsumer mPosizioniRESTConsumer;
    private final BarcodeRESTConsumer mBarcodeRESTConsumer;
    private final ColliMagazzinoRESTConsumer mColliMagazzinoRESTConsumer;
    private final ArticoloRESTConsumer mArticoloRESTConsumer;

    private boolean mShouldCheckResiduo = false;
    private boolean mShouldCheckIfExistDoc = true;
    private boolean mEnableCreation = false;

    private Listener mListener;

    public DialogScanOrCreateLUViewModel(PosizioniRESTConsumer mPosizioniRESTConsumer, BarcodeRESTConsumer barcodeRESTConsumer, ColliMagazzinoRESTConsumer colliMagazzinoRESTConsumer, ArticoloRESTConsumer articoloRESTConsumer) {
        this.mPosizioniRESTConsumer = mPosizioniRESTConsumer;
        this.mBarcodeRESTConsumer = barcodeRESTConsumer;
        this.mColliMagazzinoRESTConsumer = colliMagazzinoRESTConsumer;
        this.mArticoloRESTConsumer = articoloRESTConsumer;
    }


    public void init(boolean checkResiduo, boolean shouldCheckIfExistDoc, boolean enableCreation) {
        this.mShouldCheckResiduo = checkResiduo;
        this.mShouldCheckIfExistDoc = shouldCheckIfExistDoc;
        this.mEnableCreation = enableCreation;
    }

    public void createNewLU() {
        this.sendOnLoadingStarted();
        this.mColliMagazzinoRESTConsumer.createColloLavorazione(+1, createdMtbColt -> {
            this.sendOnLoadingEnded();
            this.sendOnLUOpened(createdMtbColt, true);
        }, this::sendError);
    }

    public void processBarcodeDTO(BarcodeScanDTO barcodeScanDTO, Runnable onComplete) {
        if (UtilityBarcode.isEtichettaPosizione(barcodeScanDTO)) {
            this.executeEtichettaPosizione(barcodeScanDTO, onComplete);
        } else if (UtilityBarcode.isEtichettaAnonima(barcodeScanDTO)) {
            this.executeEtichettaAnonima(barcodeScanDTO, onComplete);
        } else if (UtilityBarcode.isEtichetta128(barcodeScanDTO)) {
            this.executeEAN128(barcodeScanDTO, onComplete);
        } else if (UtilityBarcode.isEan13(barcodeScanDTO)) {
            this.executeEAN13(barcodeScanDTO, onComplete);
        } else {
            onComplete.run();
        }
    }


    private void executeEtichettaPosizione(BarcodeScanDTO barcodeScanDTO, Runnable onComplete) {

        MtbDepoPosizione foundPosizione = Stream.of(SettingsManager.iDB().getAvailablePosizioni())
                .filter(x -> x.getPosizione().equalsIgnoreCase(barcodeScanDTO.getStringValue()))
                .single();
        this.executePosizione(foundPosizione, onComplete);

    }

    private void executePosizione(MtbDepoPosizione posizione, Runnable onComplete) {
        this.mPosizioniRESTConsumer.getBancaliInPosizione(posizione, mtbColtList -> {

            if (mtbColtList == null || mtbColtList.size() == 0) {
                this.sendError(new NoLUFoundException());
            } else if (mtbColtList.size() == 1) {
                this.mColliMagazzinoRESTConsumer.getByTestata(mtbColtList.get(0), mShouldCheckResiduo, false, mtbColt -> {
                    onComplete.run();
                    this.sendOnLUOpened(mtbColt, false);
                }, this::sendError);
            } else {
                this.sendError(new TooManyLUFoundInMonoLUPositionException());
            }

        }, this::sendError);
    }


    private void executeEtichettaAnonima(BarcodeScanDTO barcodeScanDTO, Runnable onComplete) {
        this.mColliMagazzinoRESTConsumer.getBySSCC(barcodeScanDTO.getStringValue(), mShouldCheckResiduo, false, mtbColt -> {

            if (mtbColt == null) {
                if (mEnableCreation) {
                    this.mColliMagazzinoRESTConsumer.createColloFromEtichettaAnonima(barcodeScanDTO, GestioneEnum.LAVORAZIONE, createdMtbColt -> {
                        onComplete.run();
                        this.sendOnLUOpened(createdMtbColt, true);
                    }, this::sendError);
                } else {
                    this.sendError(new NoLUFoundException());
                }
            } else {
                if (mtbColt.getCodDtip() != null && mShouldCheckIfExistDoc) {
                    this.sendError(new AlreadyAttachedDocumentToLUException());
                } else {
                    mtbColt.setDisablePrint(true);
                    onComplete.run();
                    this.sendOnLUOpened(mtbColt, false);
                }
            }

        }, this::sendError);
    }


    private void executeEAN128(BarcodeScanDTO barcodeScanDTO, Runnable onComplete) {
        this.mBarcodeRESTConsumer.decodeEan128(barcodeScanDTO, ean128Model -> {

            if (ean128Model != null && !UtilityString.isNullOrEmpty(ean128Model.Sscc)) {

                this.mColliMagazzinoRESTConsumer.getBySSCC(ean128Model.Sscc, mShouldCheckResiduo, false, mtbColt -> {

                    if (mtbColt != null) {

                        if (mtbColt.getCodDtip() != null && mShouldCheckIfExistDoc) {
                            this.sendError(new AlreadyAttachedDocumentToLUException());
                        } else {
                            if (mtbColt.getGestioneEnum() == GestioneEnum.VENDITA && mtbColt.getSegno() == -1) {
                                this.sendOnLUVenditaConfirmRequired(confirmed -> {
                                    if (confirmed) {
                                        onComplete.run();
                                        this.sendOnLUOpened(mtbColt, false);
                                    } else {
                                        onComplete.run();
                                    }
                                });
                            } else {
                                onComplete.run();
                                this.sendOnLUOpened(mtbColt, false);
                            }
                        }

                    } else {
                        this.sendError(new NoLUFoundException());
                    }

                }, this::sendError);

            } else {
                this.sendError(new NoLUFoundException());
            }

        }, this::sendError);
    }

    private void executeEAN13(BarcodeScanDTO barcodeScanDTO, Runnable onComplete) {
        this.mArticoloRESTConsumer.getByBarcodeProd(barcodeScanDTO.getStringValue(), articoli -> {
            if (articoli.size() == 1) {
                MtbAart articolo = articoli.get(0);
                MtbDepoPosizione posizione = UtilityPosizione.getFromCache(articolo.getPosizione());
                if (posizione != null && posizione.isFlagMonoCollo()) {
                    this.executePosizione(posizione, onComplete);
                } else {
                    this.sendError(new NoLUFoundException());
                }
            } else {
                this.sendError(new NoLUFoundException());
            }
        }, this::sendError);
    }

    private void sendOnLUVenditaConfirmRequired(RunnableArgs<Boolean> onConfirm) {
        if (this.mListener != null) mListener.onLUVenditaConfirmRequired(onConfirm);
    }

    private void sendOnLUOpened(MtbColt mtbColt, boolean created) {
        if (this.mListener != null) mListener.onLUOpened(mtbColt, created);
    }

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

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

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

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

    interface Listener extends ILoadingListener {

        void onLUVenditaConfirmRequired(RunnableArgs<Boolean> onConfirm);

        void onLUOpened(MtbColt mtbColt, boolean created);

        void onError(Exception ex);

    }

}
