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

import org.jetbrains.annotations.NotNull;

import java.util.List;

import it.integry.barcode_base_android_library.model.BarcodeScanDTO;
import it.integry.integrywmsnative.core.exception.EmptyLUException;
import it.integry.integrywmsnative.core.exception.InvalidLUException;
import it.integry.integrywmsnative.core.exception.NoLUFoundException;
import it.integry.integrywmsnative.core.exception.NoResultFromBarcodeException;
import it.integry.integrywmsnative.core.exception.TooManyLUFoundInMonoLUPositionException;
import it.integry.integrywmsnative.core.expansion.RunnableArgssss;
import it.integry.integrywmsnative.core.model.MtbAart;
import it.integry.integrywmsnative.core.model.MtbColr;
import it.integry.integrywmsnative.core.model.MtbDepoPosizione;
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.rest.model.Ean128Model;
import it.integry.integrywmsnative.core.rest.model.Ean13PesoModel;
import it.integry.integrywmsnative.core.utility.UtilityBarcode;
import it.integry.integrywmsnative.core.utility.UtilityPosizione;
import it.integry.integrywmsnative.core.utility.UtilityString;
import it.integry.integrywmsnative.view.dialogs.DialogConsts;

public class DialogScanArtViewModel {

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

    private boolean mForceOnlyUL;

    private Listener mListener;

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

    public DialogScanArtViewModel setForceOnlyUL(boolean forceOnlyUL) {
        this.mForceOnlyUL = forceOnlyUL;
        return this;
    }

    public void processBarcodeDTO(BarcodeScanDTO barcodeScanDTO, RunnableArgssss<DialogConsts.Results, MtbAart, Ean128Model, List<MtbColr>> onComplete) {
        if (UtilityBarcode.isEtichettaAnonima(barcodeScanDTO)) {
            //Cerco gli articoli presenti nell'ul dell'etichetta anonima
            this.executeEtichettaLU(barcodeScanDTO.getStringValue(), onComplete);

        } else if (UtilityBarcode.isEtichettaPosizione(barcodeScanDTO)) {
            //Cerco l'UL presente all'interno della posizione
//            this.executeEtichettaPosizione(barcodeScanDTO.getStringValue(), onComplete);

        } else if (UtilityBarcode.isEtichetta128(barcodeScanDTO)) {
            this.executeEtichettaEan128(barcodeScanDTO, onComplete);

        } else if (UtilityBarcode.isEanPeso(barcodeScanDTO) && !mForceOnlyUL) {
            this.executeEtichettaEanPeso(barcodeScanDTO, onComplete);

        } else {
            this.loadArticolo(barcodeScanDTO.getStringValue(), null, onComplete);

        }
//        else {
//            this.sendError(new Exception("Barcode non valido"));
//        }
    }


    private void executeEtichettaEan128(BarcodeScanDTO barcodeScanDTO, RunnableArgssss<DialogConsts.Results, MtbAart, Ean128Model, List<MtbColr>> onComplete) {
        this.mBarcodeRESTConsumer.decodeEan128(barcodeScanDTO, ean128Model -> {

            String barcodeProd = null;

            if (ean128Model.Sscc != null) barcodeProd = ean128Model.Sscc;
            if (ean128Model.Gtin != null) barcodeProd = ean128Model.Gtin;
            if (ean128Model.Content != null) barcodeProd = ean128Model.Content;


            if (!UtilityString.isNullOrEmpty(barcodeProd)) {
                if (!UtilityString.isNullOrEmpty(ean128Model.Sscc)) {
                    this.executeEtichettaLU(ean128Model.Sscc, onComplete);
                } else if (!mForceOnlyUL) {

                    this.loadArticolo(barcodeProd, ean128Model, onComplete);
                } else {
                    this.sendError(new Exception("Barcode non valido"));
                }
            } else {
                //EAN 128 non completo o comunque mancano i riferimenti al prodotto
                this.sendError(new NoResultFromBarcodeException(barcodeProd));
            }
        }, this::sendError);
    }

    private void executeEtichettaEanPeso(BarcodeScanDTO barcodeScanDTO, RunnableArgssss<DialogConsts.Results, MtbAart, Ean128Model, List<MtbColr>> onComplete) {

        try {
            Ean13PesoModel ean13PesoModel = Ean13PesoModel.fromBarcode(barcodeScanDTO.getStringValue());

            this.loadArticolo(ean13PesoModel.getPrecode(), ean13PesoModel.toEan128(), onComplete);
        } catch (Exception ex) {
            this.sendError(ex);
        }
    }


    private void executeEtichettaLU(String SSCC, RunnableArgssss<DialogConsts.Results, MtbAart, Ean128Model, List<MtbColr>> onComplete) {
        mColliMagazzinoRESTConsumer.getBySSCC(SSCC, true, false, mtbColt -> {

            if (mtbColt != null && mtbColt.getMtbColr() != null && mtbColt.getMtbColr().size() > 0) {
                if (mtbColt.getSegno() != -1) {
                    onComplete.run(DialogConsts.Results.YES, null, null, mtbColt.getMtbColr());
                } else this.sendError(new InvalidLUException());
            } else {
                this.sendError(new EmptyLUException());
            }

        }, this::sendError);
    }

    private void executePosizione(MtbDepoPosizione posizione, MtbAart articolo, RunnableArgssss<DialogConsts.Results, MtbAart, Ean128Model, List<MtbColr>> 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), true, false, mtbColt -> {
                    onComplete.run(DialogConsts.Results.YES, articolo, null, mtbColt.getMtbColr());
                }, this::sendError);
            } else {
                this.sendError(new TooManyLUFoundInMonoLUPositionException());
            }

        }, this::sendError);
    }


    private void loadArticolo(@NotNull String barcodeProd, Ean128Model ean128Model, RunnableArgssss<DialogConsts.Results, MtbAart, Ean128Model, List<MtbColr>> onComplete) {
        this.mArticoloRESTConsumer.getByBarcodeProd(barcodeProd, mtbAartList -> {
            if (mtbAartList != null && mtbAartList.size() > 0) {

                MtbAart firstArt = mtbAartList.get(0);
                MtbDepoPosizione firstArtPosition = UtilityPosizione.getFromCache(firstArt.getPosizione());

                if (firstArtPosition != null && firstArtPosition.isFlagMonoCollo() && mForceOnlyUL) {
                    this.executePosizione(firstArtPosition, firstArt, onComplete);
                } else if (!mForceOnlyUL) {
                    onComplete.run(DialogConsts.Results.YES, mtbAartList.get(0), ean128Model, null);
                } else {
                    this.sendError(new NoResultFromBarcodeException(barcodeProd));
                }

            } else {
                this.sendError(new NoResultFromBarcodeException(barcodeProd));
            }
        }, this::sendError);
    }


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

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

    public interface Listener {

        void onError(Exception ex);
    }


}
