package it.integry.integrywmsnative.gest.ordini_uscita_elenco;

import android.content.Context;
import android.os.Bundle;
import android.text.Html;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;

import androidx.appcompat.widget.AppCompatTextView;
import androidx.core.content.res.ResourcesCompat;
import androidx.databinding.DataBindingUtil;
import androidx.databinding.ObservableArrayList;
import androidx.recyclerview.widget.LinearLayoutManager;

import com.annimon.stream.ComparatorCompat;
import com.annimon.stream.Stream;
import com.google.android.material.datepicker.MaterialDatePicker;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.Objects;

import javax.inject.Inject;

import it.integry.barcode_base_android_library.model.BarcodeScanDTO;
import it.integry.integrywmsnative.MainApplication;
import it.integry.integrywmsnative.R;
import it.integry.integrywmsnative.core.barcode_reader.BarcodeCallbackDTO;
import it.integry.integrywmsnative.core.barcode_reader.BarcodeManager;
import it.integry.integrywmsnative.core.data_cache.DataCache;
import it.integry.integrywmsnative.core.di.BindableBoolean;
import it.integry.integrywmsnative.core.expansion.BaseFragment;
import it.integry.integrywmsnative.core.expansion.OnGeneralChangedCallback;
import it.integry.integrywmsnative.core.expansion.RunnableArgs;
import it.integry.integrywmsnative.core.interfaces.IScrollableFragment;
import it.integry.integrywmsnative.core.interfaces.ISelectAllFragment;
import it.integry.integrywmsnative.core.interfaces.ITitledFragment;
import it.integry.integrywmsnative.core.model.JtbComt;
import it.integry.integrywmsnative.core.model.MtbColr;
import it.integry.integrywmsnative.core.model.MtbColt;
import it.integry.integrywmsnative.core.model.MtbDepo;
import it.integry.integrywmsnative.core.model.MtbGrup;
import it.integry.integrywmsnative.core.model.OrdineInevasoDTO;
import it.integry.integrywmsnative.core.model.secondary.GestioneEnum;
import it.integry.integrywmsnative.core.rest.consumers.ArticoloRESTConsumer;
import it.integry.integrywmsnative.core.rest.consumers.CommessaRESTConsumer;
import it.integry.integrywmsnative.core.rest.consumers.DepositoRESTConsumer;
import it.integry.integrywmsnative.core.rest.model.OrdineUscitaInevasoDTO;
import it.integry.integrywmsnative.core.rest.model.SitArtOrdDTO;
import it.integry.integrywmsnative.core.settings.SettingsManager;
import it.integry.integrywmsnative.core.utility.UtilityDate;
import it.integry.integrywmsnative.core.utility.UtilityExceptions;
import it.integry.integrywmsnative.core.utility.UtilityString;
import it.integry.integrywmsnative.databinding.FragmentMainOrdiniUscitaBinding;
import it.integry.integrywmsnative.gest.ordini_uscita_elenco.filters.FilterAgenteLayoutView;
import it.integry.integrywmsnative.gest.ordini_uscita_elenco.filters.FilterAutomezzoLayoutView;
import it.integry.integrywmsnative.gest.ordini_uscita_elenco.filters.FilterClienteLayoutView;
import it.integry.integrywmsnative.gest.ordini_uscita_elenco.filters.FilterDepositoLayoutView;
import it.integry.integrywmsnative.gest.ordini_uscita_elenco.filters.FilterGruppoMercLayoutView;
import it.integry.integrywmsnative.ui.filter_chips.filters.FilterNumeroOrdineLayoutView;
import it.integry.integrywmsnative.gest.ordini_uscita_elenco.filters.FilterPaeseLayoutView;
import it.integry.integrywmsnative.gest.ordini_uscita_elenco.filters.FilterTermConsLayoutView;
import it.integry.integrywmsnative.gest.ordini_uscita_elenco.filters.FilterVettoreLayoutView;
import it.integry.integrywmsnative.gest.ordini_uscita_elenco.filters.FilterViaggioLayoutView;
import it.integry.integrywmsnative.gest.ordini_uscita_elenco.filters.VenditaFiltroOrdiniViewModel;
import it.integry.integrywmsnative.gest.ordini_uscita_elenco.ui.OrdiniUscitaElencoAdapter;
import it.integry.integrywmsnative.gest.ordini_uscita_elenco.ui.OrdiniUscitaElencoListModel;
import it.integry.integrywmsnative.gest.prod_accettazione_ord_produzione.filters.FilterCommessaLayoutView;
import it.integry.integrywmsnative.gest.spedizione.SpedizioneActivity;
import it.integry.integrywmsnative.gest.spedizione.dialogs.row_info.BaseDialogRowInfoView;
import it.integry.integrywmsnative.ui.ElevatedToolbar;
import it.integry.integrywmsnative.ui.filter_chips.FilterChipDTO;
import it.integry.integrywmsnative.ui.filter_chips.FilterChipView;
import it.integry.integrywmsnative.view.dialogs.base.DialogSimpleMessageView;

public class OrdiniUscitaElencoFragment extends BaseFragment implements ITitledFragment, IScrollableFragment, ISelectAllFragment, OrdiniUscitaElencoViewModel.Listener {

    public BindableBoolean fabVisible = new BindableBoolean(false);

    @Inject
    DepositoRESTConsumer mDepositoRESTConsumer;

    @Inject
    ArticoloRESTConsumer mArticoloRESTConsumer;

    @Inject
    CommessaRESTConsumer mCommessaRESTConsumer;

    @Inject
    OrdiniUscitaElencoViewModel mViewModel;

    private final VenditaFiltroOrdiniViewModel mAppliedFilterViewModel = new VenditaFiltroOrdiniViewModel();

    private FragmentMainOrdiniUscitaBinding mBindings = null;

    private final ObservableArrayList<OrdiniUscitaElencoListModel> mOrdiniInevasiMutableData = new ObservableArrayList<>();

    private GestioneEnum mCurrentGestioneOrd = null;
    private GestioneEnum mCurrentGestioneCol = null;
    private int mCurrentSegnoCol = 0;
    private Class<? extends BaseDialogRowInfoView> mDialogRowInfo;

    private ElevatedToolbar mToolbar;
    private final List<Runnable> mOnPreDestroyList = new ArrayList<>();

    private int barcodeScannerIstanceID = -1;

    private List<MtbDepo> mtbDepoCache;
    private List<MtbGrup> mtbGrupCache;
    private List<JtbComt> jtbComtCache;

    public OrdiniUscitaElencoFragment() {
        // Required empty public constructor
    }

    public static OrdiniUscitaElencoFragment newInstance(GestioneEnum gestioneOrd, GestioneEnum gestioneCol, int segnoCol, Class<? extends BaseDialogRowInfoView> dialogRowInfo) {
        OrdiniUscitaElencoFragment fragment = new OrdiniUscitaElencoFragment();
        Bundle args = new Bundle();

        args.putString("gestioneOrd", gestioneOrd.getText());
        args.putString("gestioneCol", gestioneCol != null ? gestioneCol.getText() : null);
        args.putInt("segnoCol", segnoCol);

        String keyDialogRowInfo = DataCache.addItem(dialogRowInfo);
        args.putString("keyDialogRowInfo", keyDialogRowInfo);

        fragment.setArguments(args);
        return fragment;
    }

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setRetainInstance(true);

        mCurrentGestioneOrd = GestioneEnum.fromString(getArguments().getString("gestioneOrd"));
        String gestioneCol = getArguments().getString("gestioneCol");
        mCurrentGestioneCol = gestioneCol != null ? GestioneEnum.fromString(gestioneCol) : null;
        mCurrentSegnoCol = getArguments().getInt("segnoCol");

        String keyDialogRowInfo = getArguments().getString("keyDialogRowInfo");
        mDialogRowInfo = DataCache.retrieveItem(keyDialogRowInfo);
    }

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
                             Bundle savedInstanceState) {
        super.onCreateView(inflater, container, savedInstanceState);

        mBindings = DataBindingUtil.inflate(inflater, R.layout.fragment_main_ordini_uscita, container, false);

        MainApplication.appComponent
                .prodOrdineLavorazioneElencoComponent()
                .create()
                .inject(this);

        mViewModel.setListener(this);

        mBindings.setLifecycleOwner(this);
        mBindings.setView(this);
        mBindings.setViewmodel(mViewModel);

        this.initRecyclerView();
        this.initBarcodeReader();

        this.initFilters();

        return mBindings.getRoot();
    }

    @Override
    public void onStart() {
        super.onStart();
        this.onLoadingStarted();

        this.initMtbDepoCache(() -> {
            String codMdep = SettingsManager.i().getUserSession().getDepo().getCodMdep();
            mViewModel.init(codMdep, mCurrentGestioneOrd, mCurrentGestioneCol, mCurrentSegnoCol);
        });

    }

    @Override
    public void onDestroy() {
        BarcodeManager.removeCallback(barcodeScannerIstanceID);

        for (Runnable onPreDestroy : mOnPreDestroyList) {
            onPreDestroy.run();
        }

        mViewModel.setListener(null);
        super.onDestroy();
    }

    private void initRecyclerView() {

        boolean canSelectMultipleOrdini = SettingsManager.iDB().isFlagSpedizioneCanSelectMultipleOrders();
        boolean canSelectMultipleClienti = SettingsManager.iDB().isFlagMultiClienteOrdV();

        this.mViewModel.getOrderList().observe(getViewLifecycleOwner(), v -> {
            this.onLoadingStarted();
            this.initMtbGrupsCache(() -> {
                this.initJtbComtCache(this::onLoadingEnded);
            });

            mAppliedFilterViewModel.init(mViewModel.getOrderList().getValue());

            this.refreshList(null);
        });

        OrdiniUscitaElencoAdapter ordiniUscitaElencoAdapter =
                new OrdiniUscitaElencoAdapter(getActivity(), mOrdiniInevasiMutableData)
                        .setOnGroupItemClicked(x -> {
                            if (!canSelectMultipleClienti) {
                                Stream.of(mOrdiniInevasiMutableData)
                                        .filter(y -> !y.getGroupTitle().equalsIgnoreCase(x) && y.getSelectedObservable().get())
                                        .forEach(y -> y.getSelectedObservable().set(false));
                            }

                            boolean allSelected = Stream.of(mOrdiniInevasiMutableData)
                                    .filter(y -> y.getGroupTitle().equalsIgnoreCase(x))
                                    .allMatch(y -> y.getSelectedObservable().get());

                            Stream.of(mOrdiniInevasiMutableData)
                                    .filter(y -> y.getGroupTitle().equalsIgnoreCase(x))
                                    .forEach(y -> y.getSelectedObservable().set(!allSelected));
                        })
                        .setOnItemChecked(x -> {
                            if (!canSelectMultipleClienti && x.getSelectedObservable().get()) {
                                Stream.of(mOrdiniInevasiMutableData)
                                        .filter(y -> !y.getGroupTitle().equalsIgnoreCase(x.getGroupTitle()) && y.getSelectedObservable().get())
                                        .forEach(y -> y.getSelectedObservable().set(false));
                            }

                            fabVisible.set(Stream.of(mOrdiniInevasiMutableData)
                                    .anyMatch(y -> y.getSelectedObservable().get()));
                        });

        ordiniUscitaElencoAdapter
                .setEmptyView(this.mBindings.ordiniVenditaEmptyView);

        this.mBindings.venditaMainList.setAdapter(ordiniUscitaElencoAdapter);
        this.mBindings.venditaMainList.setLayoutManager(new LinearLayoutManager(getActivity()));

//        if (mToolbar != null)
//            mToolbar.setRecyclerView(this.mBindings.venditaMainList);
    }

    private void initBarcodeReader() {
        barcodeScannerIstanceID = BarcodeManager.addCallback(new BarcodeCallbackDTO()
                .setOnScanSuccessful(onScanSuccessful)
                .setOnScanFailed(ex -> UtilityExceptions.defaultException(getActivity(), ex, false)));

        BarcodeManager.enable();
    }

    private void initFilters() {
        var onPredicateChanged = new OnGeneralChangedCallback() {
            @Override
            public void run() {
                refreshList(null);
            }
        };

        mAppliedFilterViewModel.getCurrentDepositoPredicate().addOnPropertyChangedCallback(onPredicateChanged);
        mAppliedFilterViewModel.getCurrentIdViaggioPredicate().addOnPropertyChangedCallback(onPredicateChanged);
        mAppliedFilterViewModel.getCurrentNumOrdsPredicate().addOnPropertyChangedCallback(onPredicateChanged);
        mAppliedFilterViewModel.getCurrentClientePredicate().addOnPropertyChangedCallback(onPredicateChanged);
        mAppliedFilterViewModel.getCurrentVettorePredicate().addOnPropertyChangedCallback(onPredicateChanged);
        mAppliedFilterViewModel.getCurrentAutomezzoPredicate().addOnPropertyChangedCallback(onPredicateChanged);
        mAppliedFilterViewModel.getCurrentPaesePredicate().addOnPropertyChangedCallback(onPredicateChanged);
        mAppliedFilterViewModel.getCurrentAgentePredicate().addOnPropertyChangedCallback(onPredicateChanged);
        mAppliedFilterViewModel.getCurrentTermConsPredicate().addOnPropertyChangedCallback(onPredicateChanged);
        mAppliedFilterViewModel.getCurrentDataConsPredicate().addOnPropertyChangedCallback(onPredicateChanged);
        mAppliedFilterViewModel.getCurrentGruppoMercPredicate().addOnPropertyChangedCallback(onPredicateChanged);
        mAppliedFilterViewModel.getCurrentCommessaPredicate().addOnPropertyChangedCallback(onPredicateChanged);

        List<FilterChipDTO> filterList = Stream.of(OrdiniUscitaElencoBindings.AVAILABLE_FILTERS.entrySet())
                .map(Map.Entry::getValue)
                .sortBy(FilterChipDTO::getPosizione)
                .toList();

        for (FilterChipDTO filterChipDTO : filterList) {

            FilterChipView filterChipView = new FilterChipView(
                    requireActivity(),
                    filterChipDTO.getFilterChipText(),
                    v -> initBottomSheetDialogFilter(filterChipDTO));

            switch (filterChipDTO.getID()) {
                case OrdiniUscitaElencoBindings.DEPOSITO_FILTER_ID -> {
                    mAppliedFilterViewModel.getCurrentDepositoPredicate().addOnPropertyChangedCallback(new OnGeneralChangedCallback() {
                        @Override
                        public void run() {
                            if (mAppliedFilterViewModel.getCurrentDepositoPredicate().get() == null) {
                                filterChipView.disableCloseIcon();

                                mBindings.filterChipsGroup.removeView(filterChipView);
                                mBindings.filterChipsGroup.addView(filterChipView);
                                mBindings.filterChips.smoothScrollTo(0, 0);
                            } else {
                                filterChipView.enableCloseIcon();

                                mBindings.filterChipsGroup.removeView(filterChipView);
                                mBindings.filterChipsGroup.addView(filterChipView, 0);
                                mBindings.filterChips.smoothScrollTo(0, 0);
                            }
                        }
                    });
                    filterChipView.setOnResetClicked(() -> mAppliedFilterViewModel.getCurrentDepositoPredicate().set(null));
                }
                case OrdiniUscitaElencoBindings.VIAGGIO_FILTER_ID -> {
                    mAppliedFilterViewModel.getCurrentIdViaggioPredicate().addOnPropertyChangedCallback(new OnGeneralChangedCallback() {
                        @Override
                        public void run() {
                            if (mAppliedFilterViewModel.getCurrentIdViaggioPredicate().get() == null) {
                                filterChipView.disableCloseIcon();

                                mBindings.filterChipsGroup.removeView(filterChipView);
                                mBindings.filterChipsGroup.addView(filterChipView);
                                mBindings.filterChips.smoothScrollTo(0, 0);
                            } else {
                                filterChipView.enableCloseIcon();

                                mBindings.filterChipsGroup.removeView(filterChipView);
                                mBindings.filterChipsGroup.addView(filterChipView, 0);
                                mBindings.filterChips.smoothScrollTo(0, 0);
                            }
                        }
                    });
                    filterChipView.setOnResetClicked(() -> mAppliedFilterViewModel.getCurrentIdViaggioPredicate().set(null));
                }
                case OrdiniUscitaElencoBindings.NUM_ORD_FILTER_ID -> {
                    mAppliedFilterViewModel.getCurrentNumOrdsPredicate().addOnPropertyChangedCallback(new OnGeneralChangedCallback() {
                        @Override
                        public void run() {
                            if (mAppliedFilterViewModel.getCurrentNumOrdsPredicate().get() == null) {
                                filterChipView.disableCloseIcon();

                                mBindings.filterChipsGroup.removeView(filterChipView);
                                mBindings.filterChipsGroup.addView(filterChipView);
                                mBindings.filterChips.smoothScrollTo(0, 0);
                            } else {
                                filterChipView.enableCloseIcon();

                                mBindings.filterChipsGroup.removeView(filterChipView);
                                mBindings.filterChipsGroup.addView(filterChipView, 0);
                                mBindings.filterChips.smoothScrollTo(0, 0);
                            }
                        }
                    });
                    filterChipView.setOnResetClicked(() -> mAppliedFilterViewModel.getCurrentNumOrdsPredicate().set(null));
                }
                case OrdiniUscitaElencoBindings.CLIENTE_FILTER_ID -> {
                    mAppliedFilterViewModel.getCurrentClientePredicate().addOnPropertyChangedCallback(new OnGeneralChangedCallback() {
                        @Override
                        public void run() {
                            if (mAppliedFilterViewModel.getCurrentClientePredicate().get() == null) {
                                filterChipView.disableCloseIcon();

                                mBindings.filterChipsGroup.removeView(filterChipView);
                                mBindings.filterChipsGroup.addView(filterChipView);
                                mBindings.filterChips.smoothScrollTo(0, 0);
                            } else {
                                filterChipView.enableCloseIcon();

                                mBindings.filterChipsGroup.removeView(filterChipView);
                                mBindings.filterChipsGroup.addView(filterChipView, 0);
                                mBindings.filterChips.smoothScrollTo(0, 0);
                            }
                        }
                    });
                    filterChipView.setOnResetClicked(() -> mAppliedFilterViewModel.getCurrentClientePredicate().set(null));
                }
                case OrdiniUscitaElencoBindings.VETTORE_FILTER_ID -> {
                    mAppliedFilterViewModel.getCurrentVettorePredicate().addOnPropertyChangedCallback(new OnGeneralChangedCallback() {
                        @Override
                        public void run() {
                            if (mAppliedFilterViewModel.getCurrentVettorePredicate().get() == null) {
                                filterChipView.disableCloseIcon();

                                mBindings.filterChipsGroup.removeView(filterChipView);
                                mBindings.filterChipsGroup.addView(filterChipView);
                                mBindings.filterChips.smoothScrollTo(0, 0);
                            } else {
                                filterChipView.enableCloseIcon();

                                mBindings.filterChipsGroup.removeView(filterChipView);
                                mBindings.filterChipsGroup.addView(filterChipView, 0);
                                mBindings.filterChips.smoothScrollTo(0, 0);
                            }
                        }
                    });
                    filterChipView.setOnResetClicked(() -> mAppliedFilterViewModel.getCurrentVettorePredicate().set(null));
                }
                case OrdiniUscitaElencoBindings.AUTOMEZZO_FILTER_ID -> {
                    mAppliedFilterViewModel.getCurrentAutomezzoPredicate().addOnPropertyChangedCallback(new OnGeneralChangedCallback() {
                        @Override
                        public void run() {
                            if (mAppliedFilterViewModel.getCurrentAutomezzoPredicate().get() == null) {
                                filterChipView.disableCloseIcon();

                                mBindings.filterChipsGroup.removeView(filterChipView);
                                mBindings.filterChipsGroup.addView(filterChipView);
                                mBindings.filterChips.smoothScrollTo(0, 0);
                            } else {
                                filterChipView.enableCloseIcon();

                                mBindings.filterChipsGroup.removeView(filterChipView);
                                mBindings.filterChipsGroup.addView(filterChipView, 0);
                                mBindings.filterChips.smoothScrollTo(0, 0);
                            }
                        }
                    });
                    filterChipView.setOnResetClicked(() -> mAppliedFilterViewModel.getCurrentAutomezzoPredicate().set(null));
                }
                case OrdiniUscitaElencoBindings.PAESE_FILTER_ID -> {
                    mAppliedFilterViewModel.getCurrentPaesePredicate().addOnPropertyChangedCallback(new OnGeneralChangedCallback() {
                        @Override
                        public void run() {
                            if (mAppliedFilterViewModel.getCurrentPaesePredicate().get() == null) {
                                filterChipView.disableCloseIcon();

                                mBindings.filterChipsGroup.removeView(filterChipView);
                                mBindings.filterChipsGroup.addView(filterChipView);
                                mBindings.filterChips.smoothScrollTo(0, 0);
                            } else {
                                filterChipView.enableCloseIcon();

                                mBindings.filterChipsGroup.removeView(filterChipView);
                                mBindings.filterChipsGroup.addView(filterChipView, 0);
                                mBindings.filterChips.smoothScrollTo(0, 0);
                            }
                        }
                    });
                    filterChipView.setOnResetClicked(() -> mAppliedFilterViewModel.getCurrentPaesePredicate().set(null));
                }
                case OrdiniUscitaElencoBindings.AGENTE_FILTER_ID -> {
                    mAppliedFilterViewModel.getCurrentAgentePredicate().addOnPropertyChangedCallback(new OnGeneralChangedCallback() {
                        @Override
                        public void run() {
                            if (mAppliedFilterViewModel.getCurrentAgentePredicate().get() == null) {
                                filterChipView.disableCloseIcon();

                                mBindings.filterChipsGroup.removeView(filterChipView);
                                mBindings.filterChipsGroup.addView(filterChipView);
                                mBindings.filterChips.smoothScrollTo(0, 0);
                            } else {
                                filterChipView.enableCloseIcon();

                                mBindings.filterChipsGroup.removeView(filterChipView);
                                mBindings.filterChipsGroup.addView(filterChipView, 0);
                                mBindings.filterChips.smoothScrollTo(0, 0);
                            }
                        }
                    });
                    filterChipView.setOnResetClicked(() -> mAppliedFilterViewModel.getCurrentAgentePredicate().set(null));
                }
                case OrdiniUscitaElencoBindings.TERM_CONS_FILTER_ID -> {
                    mAppliedFilterViewModel.getCurrentTermConsPredicate().addOnPropertyChangedCallback(new OnGeneralChangedCallback() {
                        @Override
                        public void run() {
                            if (mAppliedFilterViewModel.getCurrentTermConsPredicate().get() == null) {
                                filterChipView.disableCloseIcon();

                                mBindings.filterChipsGroup.removeView(filterChipView);
                                mBindings.filterChipsGroup.addView(filterChipView);
                                mBindings.filterChips.smoothScrollTo(0, 0);
                            } else {
                                filterChipView.enableCloseIcon();

                                mBindings.filterChipsGroup.removeView(filterChipView);
                                mBindings.filterChipsGroup.addView(filterChipView, 0);
                                mBindings.filterChips.smoothScrollTo(0, 0);
                            }
                        }
                    });
                    filterChipView.setOnResetClicked(() -> mAppliedFilterViewModel.getCurrentTermConsPredicate().set(null));
                }
                case OrdiniUscitaElencoBindings.DATA_CONS_FILTER_ID -> {
                    mAppliedFilterViewModel.getCurrentDataConsPredicate().addOnPropertyChangedCallback(new OnGeneralChangedCallback() {
                        @Override
                        public void run() {
                            if (mAppliedFilterViewModel.getCurrentDataConsPredicate().get() == null) {
                                filterChipView.disableCloseIcon();

                                mBindings.filterChipsGroup.removeView(filterChipView);
                                mBindings.filterChipsGroup.addView(filterChipView);
                                mBindings.filterChips.smoothScrollTo(0, 0);
                            } else {
                                filterChipView.enableCloseIcon();

                                mBindings.filterChipsGroup.removeView(filterChipView);
                                mBindings.filterChipsGroup.addView(filterChipView, 0);
                                mBindings.filterChips.smoothScrollTo(0, 0);
                            }
                        }
                    });
                    filterChipView.setOnResetClicked(() -> {
                        mAppliedFilterViewModel.setDataConsegnaFilter(null);
                        mAppliedFilterViewModel.getCurrentDataConsPredicate().set(null);
                    });
                }
                case OrdiniUscitaElencoBindings.GRUPPO_MERC_FILTER_ID -> {
                    mAppliedFilterViewModel.getCurrentGruppoMercPredicate().addOnPropertyChangedCallback(new OnGeneralChangedCallback() {
                        @Override
                        public void run() {
                            if (mAppliedFilterViewModel.getCurrentGruppoMercPredicate().get() == null) {
                                filterChipView.disableCloseIcon();

                                mBindings.filterChipsGroup.removeView(filterChipView);
                                mBindings.filterChipsGroup.addView(filterChipView);
                                mBindings.filterChips.smoothScrollTo(0, 0);
                            } else {
                                filterChipView.enableCloseIcon();

                                mBindings.filterChipsGroup.removeView(filterChipView);
                                mBindings.filterChipsGroup.addView(filterChipView, 0);
                                mBindings.filterChips.smoothScrollTo(0, 0);
                            }
                        }
                    });
                    filterChipView.setOnResetClicked(() -> {
                        mAppliedFilterViewModel.setGruppoMercFilter(null);
                        mAppliedFilterViewModel.getCurrentGruppoMercPredicate().set(null);
                    });
                }
                case OrdiniUscitaElencoBindings.COMMESSA_FILTER_ID -> {
                    mAppliedFilterViewModel.getCurrentCommessaPredicate().addOnPropertyChangedCallback(new OnGeneralChangedCallback() {
                        @Override
                        public void run() {
                            if (mAppliedFilterViewModel.getCurrentCommessaPredicate().get() == null) {
                                filterChipView.disableCloseIcon();

                                mBindings.filterChipsGroup.removeView(filterChipView);
                                mBindings.filterChipsGroup.addView(filterChipView);
                                mBindings.filterChips.smoothScrollTo(0, 0);
                            } else {
                                filterChipView.enableCloseIcon();

                                mBindings.filterChipsGroup.removeView(filterChipView);
                                mBindings.filterChipsGroup.addView(filterChipView, 0);
                                mBindings.filterChips.smoothScrollTo(0, 0);
                            }
                        }
                    });
                    filterChipView.setOnResetClicked(() -> {
                        mAppliedFilterViewModel.setCommessaFilter(null);
                        mAppliedFilterViewModel.getCurrentCommessaPredicate().set(null);
                    });
                }
            }

            this.mBindings.filterChipsGroup.addView(filterChipView);
        }


    }

    private void initBottomSheetDialogFilter(FilterChipDTO filterChipDTO) {
        if (filterChipDTO.getID() == OrdiniUscitaElencoBindings.DATA_CONS_FILTER_ID) {
            var datePicker =
                    MaterialDatePicker.Builder.datePicker()
                            .setTitleText(filterChipDTO.getFilterChipText())
                            .setSelection(this.mAppliedFilterViewModel.getSelectedDataCons() != null ? this.mAppliedFilterViewModel.getSelectedDataCons().getTime() : null)
                            .build();

            datePicker.addOnPositiveButtonClickListener(selection -> {
                this.mAppliedFilterViewModel.setDataConsegnaFilter(new Date(selection));
            });
            datePicker.show(requireActivity().getSupportFragmentManager(), "TAG");
            return;
        }

        filterChipDTO
                .getFilterLayoutView()
                .setFilterName(filterChipDTO.getFilterChipText())
                .setContext(requireActivity());

        var filterLayoutView = filterChipDTO
                .getFilterLayoutView();

        switch (filterChipDTO.getID()) {
            case OrdiniUscitaElencoBindings.COMMESSA_FILTER_ID ->
                    ((FilterCommessaLayoutView) filterLayoutView)
                            .setAllCommesse(mAppliedFilterViewModel.getAllCommesse(this.jtbComtCache))
                            .setAvailableCommesse(mAppliedFilterViewModel.getAvailableCommesse(this.jtbComtCache))
                            .setOnFilterApplied(mAppliedFilterViewModel::setCommessaFilter)
                            .setPreSelectedCommesse(Stream.of(Objects.requireNonNull(mViewModel.getOrderList().getValue()))
                                    .filter(mAppliedFilterViewModel.getCurrentCommessaPredicate().get() == null ?
                                            x -> false :
                                            mAppliedFilterViewModel.getCurrentCommessaPredicate().get())
                                    .map(x -> Stream.of(jtbComtCache).filter(y -> x.getCodJcom().equalsIgnoreCase(y.getCodJcom())).findFirst().get())
                                    .toList());
            case OrdiniUscitaElencoBindings.DEPOSITO_FILTER_ID ->
                    ((FilterDepositoLayoutView) filterLayoutView)
                            .setAllCodMdeps(mAppliedFilterViewModel.getAllCodMdeps(mtbDepoCache))
                            .setAvailableCodMdeps(mAppliedFilterViewModel.getAvailableCodMdeps(mtbDepoCache))
                            .setOnFilterApplied(mAppliedFilterViewModel::setDepositoFilter)
                            .setPreSelectedCodMdeps(Stream.of(Objects.requireNonNull(mViewModel.getOrderList().getValue()))
                                    .filter(mAppliedFilterViewModel.getCurrentDepositoPredicate().get() == null ?
                                            x -> false :
                                            mAppliedFilterViewModel.getCurrentDepositoPredicate().get())
                                    .map(x -> Stream.of(mtbDepoCache).filter(y -> x.getCodMdep().equalsIgnoreCase(y.getCodMdep())).findFirst().get())
                                    .toList());
            case OrdiniUscitaElencoBindings.VIAGGIO_FILTER_ID ->
                    ((FilterViaggioLayoutView) filterLayoutView)
                            .setAllIDViaggio(mAppliedFilterViewModel.getAllIDViaggio())
                            .setAvailableIDViaggio(mAppliedFilterViewModel.getAvailableIDViaggio())
                            .setOnFilterApplied(mAppliedFilterViewModel::setIDViaggioFilter)
                            .setPreSelectedIDViaggio(Stream.of(Objects.requireNonNull(mViewModel.getOrderList().getValue()))
                                    .filter(mAppliedFilterViewModel.getCurrentIdViaggioPredicate().get() == null ?
                                            x -> false :
                                            mAppliedFilterViewModel.getCurrentIdViaggioPredicate().get())
                                    .map(OrdineUscitaInevasoDTO::getIdViaggio)
                                    .toList());
            case OrdiniUscitaElencoBindings.NUM_ORD_FILTER_ID ->
                    ((FilterNumeroOrdineLayoutView) filterLayoutView)
                            .setAllNumOrds(mAppliedFilterViewModel.getAllNumOrds())
                            .setAvailableNumOrds(mAppliedFilterViewModel.getAvailableNumOrds())
                            .setOnFilterApplied(mAppliedFilterViewModel::setNumOrdFilter)
                            .setPreSelectedNumOrds(Stream.of(Objects.requireNonNull(mViewModel.getOrderList().getValue()))
                                    .filter(mAppliedFilterViewModel.getCurrentNumOrdsPredicate().get() == null ?
                                            x -> false :
                                            mAppliedFilterViewModel.getCurrentNumOrdsPredicate().get())
                                    .map(OrdineUscitaInevasoDTO::getNumOrd)
                                    .toList());
            case OrdiniUscitaElencoBindings.CLIENTE_FILTER_ID ->
                    ((FilterClienteLayoutView) filterLayoutView)
                            .setAllClienti(mAppliedFilterViewModel.getAllClienti())
                            .setAvailableClienti(mAppliedFilterViewModel.getAvailableClienti())
                            .setOnFilterApplied(mAppliedFilterViewModel::setClienteFilter)
                            .setPreSelectedClienti(Stream.of(Objects.requireNonNull(mViewModel.getOrderList().getValue()))
                                    .filter(mAppliedFilterViewModel.getCurrentClientePredicate().get() == null ?
                                            x -> false :
                                            mAppliedFilterViewModel.getCurrentClientePredicate().get())
                                    .map(OrdineUscitaInevasoDTO::getRagSocOrd)
                                    .toList());
            case OrdiniUscitaElencoBindings.VETTORE_FILTER_ID ->
                    ((FilterVettoreLayoutView) filterLayoutView)
                            .setAllVettori(mAppliedFilterViewModel.getAllVettori())
                            .setAvailableVettori(mAppliedFilterViewModel.getAvailableVettori())
                            .setOnFilterApplied(mAppliedFilterViewModel::setVettoreFilter)
                            .setPreSelectedVettori(Stream.of(Objects.requireNonNull(mViewModel.getOrderList().getValue()))
                                    .filter(mAppliedFilterViewModel.getCurrentVettorePredicate().get() == null ?
                                            x -> false :
                                            mAppliedFilterViewModel.getCurrentVettorePredicate().get())
                                    .map(x -> x.getCodVvet() + (!UtilityString.isNullOrEmpty(x.getCodVvet()) ? " - " + x.getDescrizioneVettore() : ""))
                                    .toList());
            case OrdiniUscitaElencoBindings.AUTOMEZZO_FILTER_ID ->
                    ((FilterAutomezzoLayoutView) filterLayoutView)
                            .setAllAutomezzi(mAppliedFilterViewModel.getAllAutomezzi())
                            .setAvailableAutomezzi(mAppliedFilterViewModel.getAvailableAutomezzi())
                            .setOnFilterApplied(mAppliedFilterViewModel::setAutomezzoFilter)
                            .setPreSelectedAutomezzi(Stream.of(Objects.requireNonNull(mViewModel.getOrderList().getValue()))
                                    .filter(mAppliedFilterViewModel.getCurrentAutomezzoPredicate().get() == null ?
                                            x -> false :
                                            mAppliedFilterViewModel.getCurrentAutomezzoPredicate().get())
                                    .map(OrdineUscitaInevasoDTO::getDescrizioneAuto)
                                    .toList());
            case OrdiniUscitaElencoBindings.PAESE_FILTER_ID ->
                    ((FilterPaeseLayoutView) filterLayoutView)
                            .setAllPaesi(mAppliedFilterViewModel.getAllPaesi())
                            .setAvailablePaesi(mAppliedFilterViewModel.getAvailablePaesi())
                            .setOnFilterApplied(mAppliedFilterViewModel::setPaeseFilter)
                            .setPreSelectedPaesi(Stream.of(Objects.requireNonNull(mViewModel.getOrderList().getValue()))
                                    .filter(mAppliedFilterViewModel.getCurrentPaesePredicate().get() == null ?
                                            x -> false :
                                            mAppliedFilterViewModel.getCurrentPaesePredicate().get())
                                    .map(OrdineUscitaInevasoDTO::getCitta)
                                    .toList());
            case OrdiniUscitaElencoBindings.AGENTE_FILTER_ID ->
                    ((FilterAgenteLayoutView) filterLayoutView)
                            .setAllAgenti(mAppliedFilterViewModel.getAllAgenti())
                            .setAvailableAgenti(mAppliedFilterViewModel.getAvailableAgenti())
                            .setOnFilterApplied(mAppliedFilterViewModel::setAgenteFilter)
                            .setPreSelectedAgenti(Stream.of(Objects.requireNonNull(mViewModel.getOrderList().getValue()))
                                    .filter(mAppliedFilterViewModel.getCurrentAgentePredicate().get() == null ?
                                            x -> false :
                                            mAppliedFilterViewModel.getCurrentAgentePredicate().get())
                                    .map(OrdineUscitaInevasoDTO::getCitta)
                                    .toList());
            case OrdiniUscitaElencoBindings.TERM_CONS_FILTER_ID ->
                    ((FilterTermConsLayoutView) filterLayoutView)
                            .setAllTermCons(mAppliedFilterViewModel.getAllTermCons())
                            .setAvailableTermCons(mAppliedFilterViewModel.getAvailableTermCons())
                            .setOnFilterApplied(mAppliedFilterViewModel::setTerminiConsegnaFilter)
                            .setPreSelectedTermCons(Stream.of(Objects.requireNonNull(mViewModel.getOrderList().getValue()))
                                    .filter(mAppliedFilterViewModel.getCurrentTermConsPredicate().get() == null ?
                                            x -> false :
                                            mAppliedFilterViewModel.getCurrentTermConsPredicate().get())
                                    .map(OrdineUscitaInevasoDTO::getCitta)
                                    .toList());
            case OrdiniUscitaElencoBindings.GRUPPO_MERC_FILTER_ID ->
                    ((FilterGruppoMercLayoutView) filterLayoutView)
                            .setAllGroupMerc(mAppliedFilterViewModel.getAllGruppoMerc(mtbGrupCache))
                            .setAvailableGroupMerc(mAppliedFilterViewModel.getAvailableGruppoMerc(mtbGrupCache))
                            .setOnFilterApplied(mAppliedFilterViewModel::setGruppoMercFilter)
                            .setPreSelectedGroupMerc(mAppliedFilterViewModel.getSelectedMtbGrup());
        }

        if (!filterLayoutView.isAdded())
            filterLayoutView.show(requireActivity().getSupportFragmentManager(), "TAG");
    }


    private final RunnableArgs<BarcodeScanDTO> onScanSuccessful = data -> {
        this.onLoadingStarted();

        this.mViewModel.processBarcodeDTO(data, this::onLoadingEnded);
    };

    private void refreshList(List<OrdiniUscitaElencoDTO> filteredList) {
        requireActivity().runOnUiThread(() -> {
            List<OrdiniUscitaElencoDTO> tmpList;

            if (filteredList != null) {
                tmpList = filteredList;
            } else if (mAppliedFilterViewModel != null) {
                mAppliedFilterViewModel.applyAllTests();
                tmpList = mAppliedFilterViewModel.getMutableFilteredOrderList().getValue();
            } else {
                tmpList = mViewModel.getOrderList().getValue();
            }

            var list = convertDataModelToListModel(tmpList);

            this.mOrdiniInevasiMutableData.clear();
            this.mOrdiniInevasiMutableData.addAll(list);

            fabVisible.set(Stream.of(mOrdiniInevasiMutableData)
                    .anyMatch(y -> y.getSelectedObservable().get()));
        });
    }

    private List<OrdiniUscitaElencoListModel> convertDataModelToListModel(List<OrdiniUscitaElencoDTO> dataList) {

        ComparatorCompat<OrdiniUscitaElencoDTO> comparator = ComparatorCompat
                .comparing(OrdiniUscitaElencoDTO::getRagSocOrd)
                .thenComparing(ComparatorCompat.comparing(x -> x.getDestinatario() != null ? x.getDestinatario() : "zzzzzzzzz"))
                .thenComparing(ComparatorCompat.comparing(OrdiniUscitaElencoDTO::getNumOrd));

        List<OrdiniUscitaElencoListModel> notHiddenElements = Stream.of(dataList)
                .filter(x -> !x.isHidden())
                .sorted(comparator)
                .map(x -> {
                    OrdiniUscitaElencoListModel listModel = new OrdiniUscitaElencoListModel();

                    if (x.isFlagEvaso()) {
                        listModel.setEtichettaColor(ResourcesCompat.getColor(getResources(), R.color.mainGreen, null));
                    } else if (x.isExistColloBoolean()) {
                        listModel.setEtichettaColor(ResourcesCompat.getColor(getResources(), R.color.colorPrimary, null));
                    } else {
                        listModel.setEtichettaColor(ResourcesCompat.getColor(getResources(), android.R.color.transparent, null));
                    }

                    listModel.setGroupTitle(x.getRagSocOrd());

                    String testataOrdString = String.format(getString(R.string.ord_ven_testata), String.valueOf(x.getNumOrd()), UtilityDate.formatDate(x.getDataOrdD(), UtilityDate.COMMONS_DATE_FORMATS.DMY_HUMAN));
                    listModel.setDescription(testataOrdString);

                    listModel.setSubDescription(x.getRifOrd());

                    if (x.getDataConsD() != null) {
                        String testataDataConsString = String.format(getString(R.string.ord_ven_testata_data_cons), UtilityDate.formatDate(x.getDataConsD(), UtilityDate.COMMONS_DATE_FORMATS.DMY_HUMAN));
                        listModel.setRightDescription(testataDataConsString);
                    }

                    listModel.setOriginalModel(x);

                    return listModel;
                })
                .toList();

        return notHiddenElements;
    }

    @Override
    public void onResume() {
        super.onResume();
        Stream.of(this.mOrdiniInevasiMutableData)
                .forEach(x -> x.getSelectedObservable().set(false));
    }

    @Override
    public void onCreateActionBar(AppCompatTextView titleText, Context context) {
        titleText.setText(context.getText(R.string.prod_ordine_lavorazione_title_fragment).toString());
    }


    public void dispatchOrders() {
        List<OrdiniUscitaElencoDTO> selectedOrders = Stream.of(this.mOrdiniInevasiMutableData)
                .filter(x -> x.getSelectedObservable().get())
                .map(OrdiniUscitaElencoListModel::getOriginalModel)
                .toList();

        this.mViewModel.loadPicking(selectedOrders, this.mAppliedFilterViewModel.getSelectedMtbGrup());
    }

    @Override
    public void onFilterNumOrderApplied(List<OrdiniUscitaElencoDTO> filteredOrder) {
        requireActivity().runOnUiThread(() -> {
            var numOrders = Stream.of(filteredOrder)
                    .map(OrdineInevasoDTO::getNumOrd)
                    .distinct()
                    .toList();
            this.mAppliedFilterViewModel.setNumOrdFilter(numOrders);
        });
    }

    @Override
    public void onOrderFiltered(List<OrdiniUscitaElencoDTO> filteredOrders) {
        refreshList(filteredOrders);
    }

    @Override
    public void onOrdersDispatched(List<OrdineUscitaInevasoDTO> orders, List<SitArtOrdDTO> sitArts, List<MtbColt> alreadyRegisteredMtbColts) {
        List<String> codMarts = Stream.of(sitArts)
                .distinctBy(SitArtOrdDTO::getCodMart)
                .map(SitArtOrdDTO::getCodMart)
                .toList();

        int alreadyRegisteredUL = alreadyRegisteredMtbColts.size();

        boolean divideByGrpMerc = SettingsManager.iDB().isGroupShippingByCommodityGroup();

        DialogSimpleMessageView.makeInfoDialog(getText(R.string.orders).toString(),
                Html.fromHtml(String.format(getActivity().getResources().getQuantityString(R.plurals.loaded_orders_message, orders.size()), orders.size())
                        + "<br />" +
                        "<b>" + codMarts.size() + "</b> " + getActivity().getResources().getQuantityString(R.plurals.ordered_articles, codMarts.size())
                        + "<br />" +
                        "<b>" + alreadyRegisteredUL + "</b> " + getActivity().getResources().getQuantityString(R.plurals.already_registered_lu, alreadyRegisteredUL)),
                null,
                () -> SpedizioneActivity.startActivity(getActivity(),
                        sitArts,
                        orders,
                        alreadyRegisteredMtbColts,
                        mCurrentGestioneCol,
                        mCurrentSegnoCol,
                        MtbColr.Causale.DEFAULT,
                        mDialogRowInfo,
                        divideByGrpMerc)
        ).show(getActivity().getSupportFragmentManager(), "tag");
    }

    @Override
    public void setScrollToolbar(ElevatedToolbar toolbar) {
        mToolbar = toolbar;
    }

    @Override
    public boolean isSelectAllButtonEnabled() {
        return SettingsManager.iDB().isFlagMultiClienteOrdV();
    }

    @Override
    public void onSelectAll() {
        boolean allSelected = Stream.of(mOrdiniInevasiMutableData)
                .allMatch(x -> x.getSelectedObservable().get());

        Stream.of(mOrdiniInevasiMutableData)
                .filter(x -> !x.getOriginalModel().isHidden())
                .forEach(x -> x.getSelectedObservable().set(!allSelected));
    }


    @Override
    public void addOnPreDestroy(Runnable onPreDestroy) {
        this.mOnPreDestroyList.add(onPreDestroy);
    }


    private void initMtbDepoCache(Runnable onComplete) {
        this.mDepositoRESTConsumer.getAll(mtbDepos -> {
            this.mtbDepoCache = mtbDepos;
            onComplete.run();
        }, this::onError);
    }


    private void initMtbGrupsCache(Runnable onComplete) {
        var codMgrpArts = Stream.of(Objects.requireNonNull(this.mViewModel.getOrderList().getValue()))
                .flatMap(x -> Stream.of(x.getAvailableClassMerc() != null ? x.getAvailableClassMerc() : new ArrayList<>()))
                .map(OrdineUscitaInevasoDTO.AvailableClassMerc::getCodMgrp)
                .withoutNulls()
                .distinct()
                .toList();

        this.mArticoloRESTConsumer.getArtsGroups(codMgrpArts, mtbGrupCache -> {
            this.mtbGrupCache = mtbGrupCache;
            onComplete.run();
        }, this::onError);
    }


    private void initJtbComtCache(Runnable onComplete) {
        if (this.mViewModel.getOrderList().getValue() == null) {
            this.jtbComtCache = new ArrayList<>();
            onComplete.run();
            return;
        }
        var jtbComts = Stream.of(Objects.requireNonNull(this.mViewModel.getOrderList().getValue()))
                .flatMap(x -> Stream.of(x.getCodJcom()))
                .distinct().withoutNulls()
                .toList();

        if (jtbComts.isEmpty()) {
            this.jtbComtCache = new ArrayList<>();
            onComplete.run();
            return;
        }

        this.mCommessaRESTConsumer.getJtbComts(jtbComts, jtbComtCache -> {
            this.jtbComtCache = jtbComtCache;
            onComplete.run();
        }, this::onError);
    }
}
