package it.integry.integrywmsnative.gest.vendita_ordine_inevaso.viewmodel;

import android.app.ProgressDialog;
import androidx.databinding.ObservableArrayList;
import androidx.databinding.ObservableField;
import androidx.recyclerview.widget.LinearLayoutManager;
import android.text.SpannableString;

import com.annimon.stream.Stream;

import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Objects;

import it.integry.integrywmsnative.R;
import it.integry.integrywmsnative.core.CommonConst;
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.ISimpleOperationCallback;
import it.integry.integrywmsnative.core.REST.consumers.PrinterRESTConsumer;
import it.integry.integrywmsnative.core.REST.model.DistribuzioneColloDTO;
import it.integry.integrywmsnative.core.barcode_reader.BarcodeManager;
import it.integry.integrywmsnative.core.expansion.RunnableArgs;
import it.integry.integrywmsnative.core.model.CommonModelConsts;
import it.integry.integrywmsnative.core.model.FiltroOrdineDTO;
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.secondary.GestioneEnum;
import it.integry.integrywmsnative.core.report.ReportManager;
import it.integry.integrywmsnative.core.settings.SettingsManager;
import it.integry.integrywmsnative.core.utility.UtilityBarcode;
import it.integry.integrywmsnative.core.utility.UtilityExceptions;
import it.integry.integrywmsnative.core.utility.UtilityProgress;
import it.integry.integrywmsnative.core.utility.UtilityString;
import it.integry.integrywmsnative.gest.vendita.dto.OrdineVenditaGroupedInevasoDTO;
import it.integry.integrywmsnative.gest.vendita.dto.PickingObjectDTO;
import it.integry.integrywmsnative.gest.vendita_ordine_inevaso.VenditaOrdineInevasoActivity;
import it.integry.integrywmsnative.gest.vendita_ordine_inevaso.core.VenditaOrdineInevasoHelper;
import it.integry.integrywmsnative.gest.vendita_ordine_inevaso.core.MainListOrdineVenditaInevasoAdapter;
import it.integry.integrywmsnative.gest.vendita_ordine_inevaso.core.interfaces.IOnOrdineVenditaRowDispatched;
import it.integry.integrywmsnative.ui.StatusBarAlert;
import it.integry.integrywmsnative.view.bottomsheet.interfaces.IOnColloClosedCallback;
import it.integry.integrywmsnative.view.bottomsheet.viewmodel.ArticoliInColloBottomSheetViewModel;

import it.integry.integrywmsnative.BR;
import it.integry.integrywmsnative.view.dialogs.DialogSimpleMessageHelper;
import it.integry.integrywmsnative.view.dialogs.input_quantity.DialogInputQuantity;
import it.integry.integrywmsnative.view.dialogs.input_quantity.QuantityDTO;
import it.integry.plugins.barcode_base_library.model.BarcodeScanDTO;

public class VenditaOrdineInevasoViewModel implements IOnColloClosedCallback, IOnOrdineVenditaRowDispatched {

    public ObservableField<Boolean> isFabVisible = new ObservableField<>();

    private VenditaOrdineInevasoActivity mActivity;
    private final ArticoliInColloBottomSheetViewModel mArticoliInColloBottomSheetViewModel;

    private final List<PickingObjectDTO> mPickingList;
    private List<List<PickingObjectDTO>> mGroupedPickingList;
    private final List<OrdineVenditaGroupedInevasoDTO> mTestateOrdini;
    private final List<MtbColt> mColliRegistrati;

    private VenditaOrdineInevasoHelper mHelper;
    private MainListOrdineVenditaInevasoAdapter mAdapter;

    private GestioneEnum defaultGestioneOfUL = null;
    private List<FiltroOrdineDTO> defaultFiltroOrdine = new ArrayList<>();
    private String defaultCodAnagOfUL = null;
    private String defaultRifOrdOfUL = null;
    private Integer defaultNumOrdOfUL = null;
    private Date defaultDataOrdOfUL = null;

    public VenditaOrdineInevasoViewModel(VenditaOrdineInevasoActivity activity, ArticoliInColloBottomSheetViewModel articoliInColloBottomSheetViewModel, List<PickingObjectDTO> pickingList, List<OrdineVenditaGroupedInevasoDTO> orders, List<MtbColt> colliRegistrati) {
        this.mActivity = activity;
        this.mArticoliInColloBottomSheetViewModel = articoliInColloBottomSheetViewModel;
        this.mPickingList = pickingList;
        this.mTestateOrdini = orders;
        this.mColliRegistrati = colliRegistrati;

        this.isFabVisible.set(true);

        this.mActivity.bindings.setVariable(BR.viewmodel, this);

        this.init();
        this.initDatiPicking();
    }

    private void init(){
        mArticoliInColloBottomSheetViewModel.setOnCloseColloCallbackListener(this);
        mArticoliInColloBottomSheetViewModel.setOnItemDeletedCallback(() -> this.refreshOrderBy(false));
        mArticoliInColloBottomSheetViewModel.setOnItemEditedCallback(() -> this.refreshOrderBy(false));

        mHelper = new VenditaOrdineInevasoHelper(mActivity);

        initRecyclerView();
    }

    private void initRecyclerView(){
        //RecyclerView setup
        mActivity.bindings.venditaOrdineMainList.setHasFixedSize(true);

        mActivity.bindings.venditaOrdineMainList.setLayoutManager(new LinearLayoutManager(mActivity));

        mAdapter = mHelper.getRightListAdapter(mActivity.bindings.venditaOrdineInevasoEmptyView);

        try {
            this.mGroupedPickingList = mHelper.getPickingListRaggruppataPerPosizione(mPickingList, true);
            mHelper.updateListModel(this.mGroupedPickingList, null);
        } catch (Exception e) {
            UtilityExceptions.defaultException(mActivity, e);
        }

        mAdapter.setOnOrdineRowDispatchCallback(this);
        mActivity.bindings.venditaOrdineMainList.setAdapter(mAdapter);
    }

    private void initDatiPicking() {
        if(this.mTestateOrdini != null && this.mTestateOrdini.size() > 0){
            List<OrdineVenditaGroupedInevasoDTO.Ordine> flatOrderArray = new ArrayList<>();

            Stream.of(this.mTestateOrdini).forEach(x -> flatOrderArray.addAll(x.ordini));

            //Definizione della gestione collo di default
            List<GestioneEnum> foundGestioni = Stream.of(flatOrderArray)
                    .map(OrdineVenditaGroupedInevasoDTO.Ordine::getGestioneEnum)
                    .withoutNulls()
                    .distinctBy(x -> x)
                    .toList();

            if(foundGestioni != null && foundGestioni.size() > 1){
                UtilityExceptions.defaultException(mActivity, new Exception("Impossibile caricare ordini di diverse gestioni"));
                mActivity.finish();
                return;
            } else if(foundGestioni != null && foundGestioni.size() == 1){
                defaultGestioneOfUL = foundGestioni.get(0);
            } else {
                defaultGestioneOfUL = GestioneEnum.VENDITA;
            }



            //Definizione del filtro ordine da applicare a tutti i colli generati
            Stream.of(flatOrderArray).forEach(x -> {
                defaultFiltroOrdine.add(new FiltroOrdineDTO()
                        .setDataOrd(x.getData())
                        .setNumOrd(x.getNumero())
                        .setGestioneOrd(x.getGestione()));
            });



            //Definizione del codAnag
            List<String> foundCodAnag = Stream.of(flatOrderArray)
                    .map(OrdineVenditaGroupedInevasoDTO.Ordine::getCodAnagOrd)
                    .withoutNulls()
                    .distinctBy(x -> x)
                    .toList();

            if(foundCodAnag != null && foundCodAnag.size() == 1){
                defaultCodAnagOfUL = foundCodAnag.get(0);
            }


            //Definizione del rifOrd
            List<String> foundRifOrd = Stream.of(flatOrderArray)
                    .map(OrdineVenditaGroupedInevasoDTO.Ordine::getRifOrd)
                    .withoutNulls()
                    .distinctBy(x -> x)
                    .toList();

            if(foundRifOrd != null && foundRifOrd.size() == 1){
                defaultRifOrdOfUL = foundRifOrd.get(0);
            }


            //Definizione del numOrd
            List<Integer> foundNumOrd = Stream.of(flatOrderArray)
                    .map(OrdineVenditaGroupedInevasoDTO.Ordine::getNumero)
                    .withoutNulls()
                    .distinctBy(x -> x)
                    .toList();

            if(foundNumOrd != null && foundNumOrd.size() == 1){
                defaultNumOrdOfUL = foundNumOrd.get(0);
            }


            //Definizione del dataOrd
            List<Date> foundDataOrd = Stream.of(flatOrderArray)
                    .map(OrdineVenditaGroupedInevasoDTO.Ordine::getData)
                    .withoutNulls()
                    .distinctBy(x -> x)
                    .toList();

            if(foundDataOrd != null && foundDataOrd.size() == 1){
                defaultDataOrdOfUL = foundDataOrd.get(0);
            }

        }
    }

    public void refreshOrderBy(boolean forceHiddenCheck){

        try {
            List<MtbColr> mtbColrs = mArticoliInColloBottomSheetViewModel.mtbColt.get() != null ? mArticoliInColloBottomSheetViewModel.mtbColt.get().getMtbColr() : null;

            this.mGroupedPickingList = mHelper.getPickingListRaggruppataPerPosizione(mPickingList, forceHiddenCheck);
            mHelper.updateListModel(this.mGroupedPickingList, mtbColrs);
        } catch (Exception e) {
            UtilityExceptions.defaultException(mActivity, e);
        }
    }

    public void applyFilter(String descriptionText) {

        mActivity.bindings.filteredArtsInListExpandableLayout.expand(true);

        mActivity.bindings.descriptionFilterText.setText(descriptionText);
    }

    public void removeListFilter() {
        for(int i = 0; i < mPickingList.size(); i++) {
            mPickingList.get(i).setTempHidden(false);
            mPickingList.get(i).setTempPickData(null);
        }

        refreshOrderBy(false);
        mActivity.bindings.filteredArtsInListExpandableLayout.collapse(true);
    }

    public void recoverUL(MtbColt recoveredMtbColt){

        for(int i = 0; i < recoveredMtbColt.getMtbColr().size(); i++){

//            MtbColr currentMtbColr = recoveredMtbColt.getMtbColr().get(i);

//            List<OrdineAccettazioneDTO.Riga> foundRows = Stream.of(groupedOrdini)
//                    .filter(x -> x.getNumOrd() == currentMtbColr.getNumOrd() &&
//                            x.getRigaOrd() == currentMtbColr.getRigaOrd()&&
//                            x.getDataOrd().equals(currentMtbColr.getDataOrdD()))
//                    .toList();
//
//            if(foundRows != null && foundRows.size() > 0){
//                OrdineAccettazioneDTO.Riga currentRow = foundRows.get(0);
//
//                currentRow.setHidden(false);
//                currentRow.setQtaRiservate(currentRow.getQtaRiservate().subtract(currentMtbColr.getQtaCol()));
//            }

        }


        setULToCurrentContext(recoveredMtbColt);
        refreshOrderBy(false);
    }

    public RunnableArgs<BarcodeScanDTO> onScanSuccessfull = data -> {

        ProgressDialog progressDialog = UtilityProgress.createDefaultProgressDialog(mActivity);

        BarcodeManager.disable();

        //Se non c'è una UL aperta
        if(!thereIsAnOpenedUL()){

            //Se è un'etichetta anonima
            if(UtilityBarcode.isEtichettaAnonima(data)){
                //Se il collo non esiste allora lo creo associandolo a questa etichetta anonima
                //invece se esiste apro un collo nuovo e cerco gli articoli presenti nell'ul
                //dell'etichetta anonima
                this.executeEtichettaAnonimaNotOpenedLU(data, progressDialog);
            } else if(UtilityBarcode.isEtichetta128(data)) {

                //Creo una nuova ul e cerco tramite etichetta ean 128 (che può indicarmi un articolo o una UL)
                this.createNewUL(null, null, progressDialog, false, false, () -> {
                    this.executeEtichettaEan128(data, progressDialog);
                });
            } else {
                this.createNewUL(null, null, progressDialog, false, false, () -> {
                    this.loadArticolo(data.getStringValue(), null, progressDialog);
                });
            }
        } else {
            if(UtilityBarcode.isEtichettaAnonima(data)){
                //Cerco gli articoli presenti nell'ul dell'etichetta anonima
                this.executeEtichettaLU(data.getStringValue(), progressDialog);
            } else if(UtilityBarcode.isEtichetta128(data)) {

                //Cerco tramite etichetta ean 128 (che può indicarmi un articolo o una UL)
                this.executeEtichettaEan128(data, progressDialog);
            } else {
                this.loadArticolo(data.getStringValue(), null, progressDialog);
            }
        }

    };

    private void executeEtichettaAnonimaNotOpenedLU(BarcodeScanDTO barcodeScanDTO, ProgressDialog progressDialog) {
        ColliMagazzinoRESTConsumer.getBySSCC(barcodeScanDTO.getStringValue(), true, false, mtbColt -> {

            if(mtbColt == null) {
                this.createNewUL(
                        UtilityBarcode.getNumColloFromULAnonima(barcodeScanDTO.getStringValue()),
                        CommonConst.Config.DEFAULT_ANONYMOUS_UL_SERIE, progressDialog,
                        true, true,
                        null);
            } else {

                this.createNewUL(
                        null,
                        null,
                        progressDialog,
                        false, false,
                        () -> searchArtFromUL(mtbColt, progressDialog)
                );
            }
            BarcodeManager.enable();

        }, ex -> {
            UtilityExceptions.defaultException(mActivity, ex, progressDialog);
            BarcodeManager.enable();
        });
    }


    private void executeEtichettaLU(String SSCC, ProgressDialog progressDialog) {
        ColliMagazzinoRESTConsumer.getBySSCC(SSCC, true, false, mtbColt -> {


            if(mtbColt != null && mtbColt.getMtbColr() != null && mtbColt.getMtbColr().size() > 0) {
                searchArtFromUL(mtbColt, progressDialog);
            } else {
                progressDialog.dismiss();
                showNoArtFoundDialog();
            }


            BarcodeManager.enable();

        }, ex -> {
            UtilityExceptions.defaultException(mActivity, ex, progressDialog);
            BarcodeManager.enable();
        });
    }


    private void executeEtichettaEan128(BarcodeScanDTO barcodeScanDTO, ProgressDialog progressDialog) {
        BarcodeRESTConsumer.decodeEan128(barcodeScanDTO, ean128Model -> {

            String barcodeProd = null;

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


            if(!UtilityString.isNullOrEmpty(barcodeProd)) {

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

                    if (barcodeProd.startsWith("0") || barcodeProd.startsWith("9")) {
                        barcodeProd = barcodeProd.substring(1, barcodeProd.length());
                    }

                    this.loadArticolo(barcodeProd, PickingObjectDTO.PickData.fromEan128(ean128Model), progressDialog);

                }


            } else {
                //EAN 128 non completo o comunque mancano i riferimenti al prodotto
                progressDialog.dismiss();
                BarcodeManager.enable();
            }
        }, ex-> {
            UtilityExceptions.defaultException(mActivity, ex, progressDialog);
            BarcodeManager.enable();
        });
    }

    private void loadArticolo(String barcodeProd, PickingObjectDTO.PickData pickData, ProgressDialog progressDialog) {
        if(barcodeProd.length() == 14) {
            barcodeProd = UtilityBarcode.convertITF14toEAN13(barcodeProd);
        }


        ArticoloRESTConsumer.getByBarcodeProd(barcodeProd, mtbAartList -> {

            if(mtbAartList != null && mtbAartList.size() > 0) {

//                if(!thereIsAnOpenedUL()){
//
//                    this.createNewUL(null, null, progressDialog, false, () -> {
//                        BarcodeManager.enable();
//                        this.searchArtInList(mtbAartList.get(0), ean128Model);
//                    });
//
//                } else {
                    this.searchArtFromAnag(mtbAartList.get(0), pickData);

                    BarcodeManager.enable();
                    progressDialog.dismiss();
//                }
//
            } else {
                BarcodeManager.enable();
                progressDialog.dismiss();

                DialogSimpleMessageHelper.makeWarningDialog(mActivity,
                        new SpannableString(mActivity.getResources().getText(R.string.no_result_from_barcode)),
                        null, null)
                        .show();
            }

        }, ex -> {
            BarcodeManager.enable();
            UtilityExceptions.defaultException(mActivity, ex, progressDialog);
        });


    }


    private void searchArtFromUL(MtbColt scannedUL, ProgressDialog progressDialog) {

        final List<PickingObjectDTO> pickingList = mPickingList;

        List<PickingObjectDTO> matchPickingObject = Stream.of(pickingList)
                .filter(x -> Objects.equals(x.getNumCollo(), scannedUL.getNumCollo()) &&
                        x.getDataColloS().equals(scannedUL.getDataColloS()) &&
                        x.getSerCollo().equalsIgnoreCase(scannedUL.getSerCollo()) &&
                        (scannedUL.getGestioneEnum() == GestioneEnum.ACQUISTO || scannedUL.getGestioneEnum() == GestioneEnum.LAVORAZIONE)).toList();


        //Cerco se devo fare pick dell'articolo tramite codMart perché forse non risulta in nessun collo
        //if(matchPickingObject != null && matchPickingObject.size() == 0 && scannedUL.getMtbColr() != null && scannedUL.getMtbColr().size() > 0) {
            List<String> listOfCodMartsInRowCollo = Stream.of(scannedUL.getMtbColr())
                    .map(MtbColr::getCodMart)
                    .withoutNulls()
                    .toList();

            List<PickingObjectDTO> matchPickingObjectByArt = Stream.of(pickingList)
                    .filter(x -> //x.getNumCollo() == null &&
                                (listOfCodMartsInRowCollo.contains(x.getCodMart())))
                    .toList();


            if(SettingsManager.iDB().isEnableCheckPartitaMagCheckPickingV()) {
                for (int i = 0; i < matchPickingObjectByArt.size(); i++) {
                    PickingObjectDTO tmpPickObj = matchPickingObjectByArt.get(i);



                    List<MtbColr> matchWithPartitaMag = Stream.of(scannedUL.getMtbColr())
                            .filter(x -> x.getCodMart().equalsIgnoreCase(tmpPickObj.getCodMart()) &&
                                         Objects.equals(x.getPartitaMag(), tmpPickObj.getPartitaMag())).toList();

                    boolean anyMatch = matchWithPartitaMag.size() > 0;

                    if(!anyMatch) {
                        matchPickingObjectByArt.remove(i);
                        i--;
                    } else if(matchWithPartitaMag.size() == 1){
                        MtbColr matchRow = matchWithPartitaMag.get(0);

                        PickingObjectDTO.PickData pickData = new PickingObjectDTO.PickData()
                                .setBatchLot(matchRow.getPartitaMag())
                                .setDataScad(matchRow.getDataScadPartitaD())
                                .setNumCnf(matchRow.getNumCnf())
                                .setQtaCnf(matchRow.getQtaCnf())
                                .setQtaTot(matchRow.getQtaCol())
                                .setSourceMtbColt(scannedUL);

                        tmpPickObj.setTempPickData(pickData);
                    }
                }

            } else {
                for (int i = 0; i < matchPickingObjectByArt.size(); i++) {

                    PickingObjectDTO tmpPickObj = matchPickingObjectByArt.get(i);
                    List<MtbColr> matchWithColloRow = Stream.of(scannedUL.getMtbColr())
                            .filter(x -> x.getCodMart().equalsIgnoreCase(tmpPickObj.getCodMart())).toList();

                    if(matchWithColloRow.size() == 1){
                        MtbColr matchRow = matchWithColloRow.get(0);

                        PickingObjectDTO.PickData pickData = new PickingObjectDTO.PickData()
                                .setBatchLot(matchRow.getPartitaMag())
                                .setDataScad(matchRow.getDataScadPartitaD())
                                .setNumCnf(matchRow.getNumCnf())
                                .setQtaCnf(matchRow.getQtaCnf())
                                .setQtaTot(matchRow.getQtaCol())
                                .setSourceMtbColt(scannedUL);

                        tmpPickObj.setTempPickData(pickData);
                    }

                }
            }




        //}
        matchPickingObject.addAll(matchPickingObjectByArt);

        this.loadMatchedRows(matchPickingObject);

        progressDialog.dismiss();
        BarcodeManager.enable();

    }


    private void searchArtFromAnag(MtbAart mtbAart, PickingObjectDTO.PickData pickData) {

        final List<PickingObjectDTO> pickingList = mPickingList;

        List<PickingObjectDTO> matchPickingObject = Stream.of(pickingList)
                .filter(x -> x.getNumCollo() == null &&
                        (mtbAart.getCodMart().equalsIgnoreCase(x.getCodMart())))
                .toList();


        if(SettingsManager.iDB().isEnableCheckPartitaMagCheckPickingV()) {
            List<PickingObjectDTO> matchWithPartitaMag = Stream.of(matchPickingObject)
                    .filter(x -> x.getCodMart().equalsIgnoreCase(mtbAart.getCodMart()) &&
                            Objects.equals(x.getPartitaMag(), pickData.getBatchLot())).toList();

            matchPickingObject = matchWithPartitaMag;

        }

        if(matchPickingObject.size() == 1){
            matchPickingObject.get(0).setTempPickData(pickData);
        }

        this.loadMatchedRows(matchPickingObject);
    }


    private void loadMatchedRows(List<PickingObjectDTO> matchedRows) {
        if(matchedRows == null || matchedRows.size() == 0) {
            showNoArtFoundDialog();
        } else if(matchedRows.size() == 1) {
            onOrdineRowDispatch(matchedRows.get(0));
        } else {
            for(int i = 0; i < mPickingList.size(); i++) {
                if(!matchedRows.contains(mPickingList.get(i))) {
                    mPickingList.get(i).setTempHidden(true);
                }
            }



            applyFilter("");
            refreshOrderBy(false);
        }
    }

    private void showNoArtFoundDialog() {
        DialogSimpleMessageHelper.makeWarningDialog(mActivity,
                new SpannableString(mActivity.getResources().getText(R.string.no_result_from_barcode)),
                null, null).show();
    }


    public void createNewUL() {
        this.createNewUL(null, null, null, false, true, null);
    }

    public void createNewUL(Integer customNumCollo, String customSerCollo, ProgressDialog progress, boolean disablePrint, boolean closeProgress, Runnable onComplete) {
        mActivity.bindings.venditaOrdineInevasoFab.close(true);

        if (progress == null){
            progress = UtilityProgress.createDefaultProgressDialog(mActivity);
        }
        progress.show();

        MtbColt mtbColt = new MtbColt();
        mtbColt .setGestione(defaultGestioneOfUL)
                .setSegno(-1)
                .setRifOrd(defaultRifOrdOfUL)
                .setNumOrd(defaultNumOrdOfUL)
                .setDataOrdD(defaultDataOrdOfUL)
                .setCodAnag(defaultCodAnagOfUL)
                .setOperation(CommonModelConsts.OPERATION.INSERT_OR_UPDATE);

        if(customNumCollo != null) {
            mtbColt.setNumCollo(customNumCollo);
        }

        if(!UtilityString.isNullOrEmpty(customSerCollo)) {
            mtbColt.setSerCollo(customSerCollo);
        }

        mtbColt.generaFiltroOrdineFromDTO(defaultFiltroOrdine);

        ProgressDialog finalProgress = progress;
        ColliMagazzinoRESTConsumer.saveCollo(mtbColt, new ISimpleOperationCallback<MtbColt>() {
            @Override
            public void onSuccess(MtbColt value) {

                value
                        .setDisablePrint(disablePrint)
                        .setMtbColr(new ObservableArrayList<>());

                setULToCurrentContext(value);

                if(closeProgress) finalProgress.dismiss();

                new StatusBarAlert.Builder(mActivity)
                        .autoHide(true)
                        .withDuration(2500)
                        .showProgress(false)
                        .withText(R.string.data_saved)
                        .withAlertColor(R.color.mainGreen)
                        .build();

                if(onComplete != null) onComplete.run();

            }

            @Override
            public void onFailed(Exception ex) {
                UtilityExceptions.defaultException(mActivity, ex, finalProgress);
            }
        });

    }

    private void setULToCurrentContext(MtbColt mtbColt){
        isFabVisible.set(false);
        mArticoliInColloBottomSheetViewModel.mtbColt.set(mtbColt);
    }

    public void showCreatedUL() {

        mActivity.bindings.venditaOrdineInevasoFab.close(false);
        mActivity.startListaBancaliRegistratiActivity((ArrayList<MtbColt>) mColliRegistrati);
    }

    @Override
    public void onColloClosed() {
        if(thereIsAnOpenedUL()) {
            final ProgressDialog progress = ProgressDialog.show(mActivity, mActivity.getText(R.string.waiting),
                    mActivity.getText(R.string.loading) + " ...", true);

            progress.show();

            if(thereIsAnyRowInUL()) {
                updateDataFine(progress, () -> distribuisciCollo(progress, () -> printCollo(progress)));
            } else {
                deleteCollo(progress);
            }

        }
    }

    private void updateDataFine(ProgressDialog progress, Runnable onComplete) {

        MtbColt cloneMtbColt = (MtbColt) mArticoliInColloBottomSheetViewModel.mtbColt.get().clone();
        cloneMtbColt.setOperation(CommonModelConsts.OPERATION.NO_OP);
        cloneMtbColt.setOraFinePrep(new Date());


        ColliMagazzinoRESTConsumer.saveCollo(cloneMtbColt, new ISimpleOperationCallback<MtbColt>() {
            @Override
            public void onSuccess(MtbColt value) {
                onComplete.run();
            }

            @Override
            public void onFailed(Exception ex) {
                UtilityExceptions.defaultException(mActivity, ex, progress);
            }
        });

    }

    private void distribuisciCollo(ProgressDialog progress, Runnable onComplete) {

        MtbColt cloneMtbColt = (MtbColt) mArticoliInColloBottomSheetViewModel.mtbColt.get().clone();

        ColliMagazzinoRESTConsumer.distribuisciCollo(cloneMtbColt, DistribuzioneColloDTO.CriterioDistribuzione.UPDATE, onComplete,
                ex -> UtilityExceptions.defaultException(mActivity, ex, progress));
    }

    private void printCollo(ProgressDialog progress) {


        PrinterRESTConsumer.getAvailablePrinters(SettingsManager.i().userSession.depo.getCodMdep(), PrinterRESTConsumer.Type.SECONDARY,new ISimpleOperationCallback<List<String>>() {
            @Override
            public void onSuccess(List<String> value) {

                if(value.size() > 0) {
                    try{
                        MtbColt currentMtbColt = mArticoliInColloBottomSheetViewModel.mtbColt.get();

                        ReportManager.getRightReportNameByMtbColt(currentMtbColt, reportName -> {

                                    PrinterRESTConsumer.printCollo(
                                            value.get(0),
                                            currentMtbColt,
                                            1, reportName, () -> {

                                                postCloseOperations();
                                                progress.dismiss();

                                            }, ex -> {

                                                progress.dismiss();
                                                String errorMessage = ex.getMessage();
                                                DialogSimpleMessageHelper.makeErrorDialog(
                                                        mActivity,
                                                        new SpannableString(errorMessage),
                                                        null,
                                                        null,
                                                        R.string.button_ignore_print,
                                                        () -> postCloseOperations()).show();
                                            });

                                    }, ex -> UtilityExceptions.defaultException(mActivity, ex, progress)
                        );
                    } catch (Exception ex) {
                        UtilityExceptions.defaultException(mActivity, ex, progress);
                        postCloseOperations();
                    }
                } else {
                    progress.dismiss();
                    String errorMessage = "Nessuna stampante configurata";
                    DialogSimpleMessageHelper.makeWarningDialog(mActivity, new SpannableString(errorMessage), null, () -> postCloseOperations()).show();
                }
            }

            @Override
            public void onFailed(Exception ex) {
                UtilityExceptions.defaultException(mActivity, ex, progress);
            }
        });
    }

    private void deleteCollo(ProgressDialog progress) {

        ColliMagazzinoRESTConsumer.deleteCollo(mArticoliInColloBottomSheetViewModel.mtbColt.get(), () -> {
                    mArticoliInColloBottomSheetViewModel.mtbColt.set(null);

                    isFabVisible.set(true);

                    progress.dismiss();
                }, ex -> UtilityExceptions.defaultException(mActivity, ex, progress)
        );
    }

    public boolean thereIsAnOpenedUL() {
        return mArticoliInColloBottomSheetViewModel.mtbColt.get() != null;
    }
    public boolean thereIsAnyRowInUL() {
        return mArticoliInColloBottomSheetViewModel.mtbColt.get() != null &&
                mArticoliInColloBottomSheetViewModel.mtbColt.get().getMtbColr() != null &&
                mArticoliInColloBottomSheetViewModel.mtbColt.get().getMtbColr().size() > 0;
    }


    private void postCloseOperations() {

        MtbColt mtbColt = mArticoliInColloBottomSheetViewModel.mtbColt.get();

        this.mColliRegistrati.add(mtbColt);

        mArticoliInColloBottomSheetViewModel.mtbColt.set(null);
        isFabVisible.set(true);

        if(mtbColt != null && mtbColt.getMtbColr() != null) {

            List<MtbColr> mtbColrs = mtbColt.getMtbColr();

            for (int i = 0; i < mtbColrs.size(); i++) {

                MtbColr x = mtbColt.getMtbColr().get(i);

                Stream.of(this.mPickingList)
                        .filter(currentRow ->
                                x.getCodMart().equalsIgnoreCase(currentRow.getCodMart()) &&
                                        ((x.getCodJcom() == null && currentRow.getCodJcom() == null) || (x.getCodJcom() != null && x.getCodJcom().equalsIgnoreCase(currentRow.getCodJcom()))) &&
                                        (!SettingsManager.iDB().isEnableCheckPartitaMagCheckPickingV() || (SettingsManager.iDB().isEnableCheckPartitaMagCheckPickingV() && ((x.getPartitaMag() == null && currentRow.getPartitaMag() == null) || (x.getPartitaMag() != null && x.getPartitaMag().equalsIgnoreCase(currentRow.getPartitaMag()))))) &&
                                        ((x.getNumColloRif() == null && currentRow.getNumCollo() == null) || (x.getNumColloRif() != null && x.getNumColloRif().equals(currentRow.getNumCollo())))
                        )

                        .forEach(currentRow -> {
                            currentRow.setQtaCollo(currentRow.getQtaCollo().subtract(x.getQtaCol()));
                            currentRow.setQtaOrd(currentRow.getQtaOrd().subtract(x.getQtaCol()));
                        });

            }
        }

        removeListFilter();
        refreshOrderBy(true);

    }


    @Override
    public void onOrdineRowDispatch(final PickingObjectDTO item) {
        if(mArticoliInColloBottomSheetViewModel.mtbColt.get() != null){

            List<MtbColr> currentMtbColrs = mArticoliInColloBottomSheetViewModel.mtbColt.get().getMtbColr();

            List<MtbColr> filteredMtbColrs = Stream.of(currentMtbColrs).filter(
                    x -> x.getCodMart().equalsIgnoreCase(item.getCodMart()) &&
                            (x.getPartitaMag() != null && x.getPartitaMag().equalsIgnoreCase(item.getPartitaMag())))
                    .toList();

            float qtaEvasaTotaleInMtbColr = 0;
            for (MtbColr mtbColr : filteredMtbColrs) {
                qtaEvasaTotaleInMtbColr += mtbColr.getQtaCol().floatValue();
            }
            float qtaEvasaTotale = qtaEvasaTotaleInMtbColr;


            filteredMtbColrs = Stream.of(currentMtbColrs).filter(
                    x ->
                            x.getGestioneRif() != null && x.getGestioneRif().equalsIgnoreCase(item.getGestione()) &&
                            Objects.equals(x.getNumColloRif(), item.getNumCollo()) &&
                            x.getSerColloRif() != null && x.getSerColloRif().equalsIgnoreCase(item.getSerCollo()) &&
                            x.getDataColloRifD() != null && x.getDataColloRifD().equals(item.getDataColloD()) &&
                            x.getCodMart() != null && x.getCodMart().equalsIgnoreCase(item.getCodMart()) &&
                            (!SettingsManager.iDB().isEnableCheckPartitaMagCheckPickingV() || (SettingsManager.iDB().isEnableCheckPartitaMagCheckPickingV() && ((x.getPartitaMag() == null && item.getPartitaMag() == null) || (x.getPartitaMag() != null && x.getPartitaMag().equalsIgnoreCase(item.getPartitaMag())))))
            ).toList();

            float qtaEvasaCurrentULInMtbColr = 0;
            for (MtbColr mtbColr : filteredMtbColrs) {
                qtaEvasaCurrentULInMtbColr += mtbColr.getQtaCol().floatValue();
            }
            float qtaEvasaCurrentUL = qtaEvasaCurrentULInMtbColr;




            BigDecimal qtaDaEvadere = item.getQtaOrd().subtract(new BigDecimal(qtaEvasaTotale));
            if(qtaDaEvadere.floatValue() < 0) qtaDaEvadere = BigDecimal.ZERO;

            BigDecimal qtaDisponibile = item.getQtaCollo().subtract(new BigDecimal(qtaEvasaCurrentUL));
            if(qtaDisponibile.floatValue() < 0) qtaDisponibile = BigDecimal.ZERO;

            DialogInputQuantity.DTO dto = new DialogInputQuantity.DTO()
                    .setBatchLot(item.getPartitaMag())
                    .setCodArtFor(item.getCodArtFor())
                    .setMtbAart(item.getMtbAart())
                    .setQtaOrd(item.getQtaOrd())
                    .setQtaDaEvadere(qtaDaEvadere)
                    .setQtaDisponibile(qtaDisponibile)
                    .setQtaTot(qtaDisponibile)
                    .setQtaEvasa(new BigDecimal(qtaEvasaTotale))
                    .setCanPartitaMagBeChanged(false)
                    .setMaxQta(qtaDisponibile);

            if(item.getTempPickData() != null) {
                PickingObjectDTO.PickData tmpPickData = item.getTempPickData();

                if(!UtilityString.isNullOrEmpty(tmpPickData.getBatchLot())) {
                    dto.setBatchLot(tmpPickData.getBatchLot());
                }

                if(tmpPickData.getDataScad() != null){
                    dto.setDataScad(tmpPickData.getDataScad());
                    dto.setShouldAskDataScad(true);
                }

                boolean useQtaDaEvadere;

                if(tmpPickData.getQtaTot() != null) {
                    useQtaDaEvadere = qtaDaEvadere.floatValue() < tmpPickData.getQtaTot().floatValue();
                    if(useQtaDaEvadere){
                        dto.setQtaTot(qtaDaEvadere);
                        dto.setMaxQta(qtaDaEvadere);
                    } else {
                        dto.setQtaTot(tmpPickData.getQtaTot());
                        dto.setMaxQta(tmpPickData.getQtaTot());
                    }


                    if (tmpPickData.getQtaCnf() != null && useQtaDaEvadere) {
                        dto.setQtaCnf(tmpPickData.getQtaCnf());
                    }
                }


                if(dto.getQtaTot() != null && dto.getQtaTot().floatValue() > 0 && dto.getQtaCnf() != null && dto.getQtaCnf().floatValue() > 0) {
                    dto.setNumCnf(dto.getQtaTot().divide(dto.getQtaCnf()).intValue());
                }


                dto.setCanPartitaMagBeChanged(false);
                dto.setCanDataScadBeChanged(false);

            }

            DialogInputQuantity.makeBase(mActivity, dto, false,  value -> onOrdineRowDispatched(item, value)).show();
        }
    }

    private void onOrdineRowDispatched(PickingObjectDTO item, QuantityDTO quantityDTO){
        final ProgressDialog progress = ProgressDialog.show(mActivity, mActivity.getText(R.string.waiting),
                mActivity.getText(R.string.loading) + " ...", true);

        final MtbColr mtbColr = new MtbColr()
                .setCodMart(item.getCodMart())
                .setPartitaMag(UtilityString.empty2null(quantityDTO.batchLot.get()))
                .setQtaCol(new BigDecimal(quantityDTO.qtaTot.get()))
                .setQtaCnf(new BigDecimal(quantityDTO.qtaCnf.get()))
                .setNumCnf(new BigDecimal(quantityDTO.numCnf.get()))
                .setDescrizione(item.getDescrizioneEstesa())
                .setDatetimeRow(new Date());

        if(item.getTempPickData() != null && item.getTempPickData().getSourceMtbColt() != null) {
            MtbColt sourceMtbColt = item.getTempPickData().getSourceMtbColt();

            mtbColr
                    .setCodJcom(UtilityString.empty2null(item.getCodJcom()))
                    .setSerColloRif(UtilityString.empty2null(sourceMtbColt.getSerCollo()))
                    .setNumColloRif(sourceMtbColt.getNumCollo())
                    .setGestioneRif(UtilityString.empty2null(sourceMtbColt.getGestione()))
                    .setDataColloRif(UtilityString.empty2null(sourceMtbColt.getDataColloS()));
        } else if(item.getNumCollo() != null) {
            mtbColr
                    .setCodJcom(UtilityString.empty2null(item.getCodJcom()))
                    .setSerColloRif(UtilityString.empty2null(item.getSerCollo()))
                    .setNumColloRif(item.getNumCollo())
                    .setGestioneRif(UtilityString.empty2null(item.getGestione()))
                    .setDataColloRif(UtilityString.empty2null(item.getDataColloS()));
        }



        mtbColr.setOperation(CommonModelConsts.OPERATION.INSERT_OR_UPDATE);

        MtbColt cloneMtbColt = (MtbColt) mArticoliInColloBottomSheetViewModel.mtbColt.get().clone();
        cloneMtbColt.setOperation(CommonModelConsts.OPERATION.NO_OP);

        cloneMtbColt.setMtbColr(new ObservableArrayList());
        cloneMtbColt.getMtbColr().add(mtbColr);

        ColliMagazzinoRESTConsumer.saveCollo(cloneMtbColt, new ISimpleOperationCallback<MtbColt>() {
            @Override
            public void onSuccess(MtbColt value) {

                mtbColr
                        .setDataCollo(value.getDataColloS())
                        .setNumCollo(value.getNumCollo())
                        .setGestione(value.getGestione())
                        .setSerCollo(value.getSerCollo())
                        .setRiga(value.getMtbColr().get(0).getRiga())
                        .setUntMis(item.getMtbAart().getUntMis())
                        .setMtbAart(item.getMtbAart());

                item.getWithdrawRows().add(mtbColr);

                mArticoliInColloBottomSheetViewModel.mtbColt.get().getMtbColr().add(mtbColr);

                //Chiamato removeListFilter perché cosi mi cancella tutti i dati di pick temporanei
                removeListFilter();

                new StatusBarAlert.Builder(mActivity)
                        .autoHide(true)
                        .withDuration(2500)
                        .showProgress(false)
                        .withText(R.string.data_saved)
                        .withAlertColor(R.color.mainGreen)
                        .build();

                progress.dismiss();
            }

            @Override
            public void onFailed(Exception ex) {
                UtilityExceptions.defaultException(mActivity, ex, progress);
            }
        });
    }

}
