package it.integry.integrywmsnative.gest.prod_accettazione_ord_produzione;


import android.content.Context;
import android.content.Intent;
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.databinding.DataBindingUtil;
import androidx.databinding.ObservableArrayList;
import androidx.fragment.app.Fragment;
import androidx.recyclerview.widget.LinearLayoutManager;

import com.annimon.stream.Stream;

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

import javax.inject.Inject;

import it.integry.integrywmsnative.MainApplication;
import it.integry.integrywmsnative.R;
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.interfaces.IScrollableFragment;
import it.integry.integrywmsnative.core.interfaces.ITitledFragment;
import it.integry.integrywmsnative.core.model.JtbComt;
import it.integry.integrywmsnative.core.rest.consumers.CommessaRESTConsumer;
import it.integry.integrywmsnative.core.settings.SettingsManager;
import it.integry.integrywmsnative.core.utility.UtilityBigDecimal;
import it.integry.integrywmsnative.core.utility.UtilityDate;
import it.integry.integrywmsnative.databinding.FragmentProdOrdineProduzioneElencoBinding;
import it.integry.integrywmsnative.gest.accettazione_ordini_elenco.dto.OrdineAccettazioneInevasoDTO;
import it.integry.integrywmsnative.gest.accettazione_ordini_elenco.dto.SitArtOrdDTO;
import it.integry.integrywmsnative.gest.accettazione_ordini_picking.AccettazioneOrdiniPickingActivity;
import it.integry.integrywmsnative.ui.filter_chips.filters.FilterNumeroOrdineLayoutView;
import it.integry.integrywmsnative.gest.prod_accettazione_ord_produzione.filters.FilterCommessaLayoutView;
import it.integry.integrywmsnative.gest.prod_accettazione_ord_produzione.filters.OrdineProduzioneFilterViewModel;
import it.integry.integrywmsnative.gest.prod_accettazione_ord_produzione.ui.MainListProdOrdineProduzioneElencoClienteListModel;
import it.integry.integrywmsnative.gest.prod_accettazione_ord_produzione.ui.MainListProdOrdineProduzioneElencoListModel;
import it.integry.integrywmsnative.gest.prod_accettazione_ord_produzione.ui.OrdineProduzioneListAdapter;
import it.integry.integrywmsnative.ui.filter_chips.FilterChipDTO;
import it.integry.integrywmsnative.ui.filter_chips.FilterChipView;
import it.integry.integrywmsnative.view.dialogs.base.DialogSimpleMessageView;

/**
 * A simple {@link Fragment} subclass.
 */
public class ProdOrdineProduzioneElencoFragment extends BaseFragment implements ProdOrdineProduzioneElencoViewModel.Listener, ITitledFragment, IScrollableFragment {

    public BindableBoolean fabVisible = new BindableBoolean(false);

    @Inject
    ProdOrdineProduzioneElencoViewModel mViewModel;

    @Inject
    CommessaRESTConsumer mCommessaRESTConsumer;

    private FragmentProdOrdineProduzioneElencoBinding mBindings;

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

    private AppCompatTextView mAppBarTitle;

    //    private DialogOrdineProduzioneFiltroAvanzatoViewModel mAppliedFilterViewModel;
    private OrdineProduzioneFilterViewModel mFilterViewModel = new OrdineProduzioneFilterViewModel();
    private List<JtbComt> jtbComtCache;

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


    public static ProdOrdineProduzioneElencoFragment newInstance() {
        ProdOrdineProduzioneElencoFragment fragment = new ProdOrdineProduzioneElencoFragment();
        Bundle args = new Bundle();
        fragment.setArguments(args);
        return fragment;
    }

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


    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
                             Bundle savedInstanceState) {
        mBindings = DataBindingUtil.inflate(inflater, R.layout.fragment_prod_ordine_produzione_elenco, container, false);

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

        mViewModel.setListener(this);

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

        this.initRecyclerView();
        this.initFilters();

        return mBindings.getRoot();
    }


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

        this.fabVisible.set(false);

        String codMdep = SettingsManager.i().getUserSession().getDepo().getCodMdep();
        mViewModel.init(codMdep);
    }

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

    private void initRecyclerView() {
        this.mViewModel.getOrderList().observe(getViewLifecycleOwner(), v -> {
            this.onLoadingStarted();
            this.initJtbComtCache(this::onLoadingEnded);

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

            this.refreshList(null);
        });

        mBindings.ordineProduzioneMainList.setLayoutManager(new LinearLayoutManager(getActivity()));

        OrdineProduzioneListAdapter adapter = new OrdineProduzioneListAdapter(getActivity(), mOrdiniInevasiMutableData)
                .setOnGroupItemClicked(x -> {
                    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 -> {
                    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()));
                });

        adapter.setEmptyView(mBindings.ordiniProduzioneEmptyView);

        mBindings.ordineProduzioneMainList.setAdapter(adapter);

//        mToolbar.setRecyclerView(mBindings.ordineProduzioneMainList);
    }

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

        mFilterViewModel.getCurrentNumOrdsPredicate().addOnPropertyChangedCallback(onPredicateChanged);
        mFilterViewModel.getCurrentCommPredicate().addOnPropertyChangedCallback(onPredicateChanged);


        for (var filterChipDTO : ProdOrdineProduzioneElencoBindings.AVAILABLE_FILTERS.entrySet()) {

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

            switch (filterChipDTO.getKey()) {
                case ProdOrdineProduzioneElencoBindings.COMMESSA_FILTER_ID:
                    mFilterViewModel.getCurrentCommPredicate().addOnPropertyChangedCallback(new OnGeneralChangedCallback() {
                        @Override
                        public void run() {
                            if (mFilterViewModel.getCurrentCommPredicate().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(() -> mFilterViewModel.getCurrentCommPredicate().set(null));
                    break;
                case ProdOrdineProduzioneElencoBindings.NUM_ORD_FILTER_ID:
                    mFilterViewModel.getCurrentNumOrdsPredicate().addOnPropertyChangedCallback(new OnGeneralChangedCallback() {
                        @Override
                        public void run() {
                            if (mFilterViewModel.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(() -> mFilterViewModel.getCurrentNumOrdsPredicate().set(null));
                    break;
            }
            this.mBindings.filterChipsGroup.addView(filterChipView);
        }
    }

    private void initBottomSheetDialogFilter(FilterChipDTO filterChipDTO) {
        filterChipDTO
                .getFilterLayoutView()
                .setFilterName(filterChipDTO.getFilterChipText())
                .setContext(requireActivity());

        var filterLayoutView = filterChipDTO
                .getFilterLayoutView();

        switch (filterChipDTO.getID()) {
            case ProdOrdineProduzioneElencoBindings.COMMESSA_FILTER_ID:
                ((FilterCommessaLayoutView) filterLayoutView)
                        .setAllCommesse(mFilterViewModel.getAllCommesse(jtbComtCache))
                        .setAvailableCommesse(mFilterViewModel.getAvailableCommesse(jtbComtCache))
                        .setOnFilterApplied(mFilterViewModel::setCommessaFilter)
                        .setPreSelectedCommesse(Stream.of(Objects.requireNonNull(mViewModel.getOrderList().getValue()))
                                .filter(mFilterViewModel.getCurrentCommPredicate().get() == null ?
                                        x -> false :
                                        mFilterViewModel.getCurrentCommPredicate().get())
                                .map(x -> Stream.of(jtbComtCache).filter(y -> x.getCodJcom().equalsIgnoreCase(y.getCodJcom())).findFirst().get())
                                .toList());
                break;
            case ProdOrdineProduzioneElencoBindings.NUM_ORD_FILTER_ID:
                ((FilterNumeroOrdineLayoutView) filterLayoutView)
                        .setAllNumOrds(mFilterViewModel.getAllNumOrds())
                        .setAvailableNumOrds(mFilterViewModel.getAvailableNumOrds())
                        .setOnFilterApplied(mFilterViewModel::setNumOrdFilter)
                        .setPreSelectedNumOrds(Stream.of(Objects.requireNonNull(mViewModel.getOrderList().getValue()))
                                .filter(mFilterViewModel.getCurrentNumOrdsPredicate().get() == null ?
                                        x -> false :
                                        mFilterViewModel.getCurrentNumOrdsPredicate().get())
                                .map(OrdineAccettazioneInevasoDTO::getNumero)
                                .toList());
                break;
        }

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

    }

    private void refreshList(List<OrdineAccettazioneInevasoDTO> filteredList) {

        List<OrdineAccettazioneInevasoDTO> tmpList = null;

        if (filteredList != null) {
            tmpList = filteredList;
        } else if (mFilterViewModel != null) {
            mFilterViewModel.applyAllTests();
            tmpList = mFilterViewModel.getMutableFilteredOrderList().getValue();
        } else {
            tmpList = mViewModel.getOrderList().getValue();
        }
        this.mOrdiniInevasiMutableData.clear();
        if (tmpList != null) {
            this.mOrdiniInevasiMutableData.addAll(convertDataModelToListModel(tmpList));
        }
    }

    private List<MainListProdOrdineProduzioneElencoListModel> convertDataModelToListModel(List<OrdineAccettazioneInevasoDTO> dataList) {

        return Stream.of(dataList)
                //.distinctBy(OrdineAccettazioneInevasoDTO::getBarcode)
                .sortBy(x -> x.getRagSocOrd() + (x.getDataConsD() != null ? UtilityDate.formatDate(x.getDataConsD(), UtilityDate.COMMONS_DATE_FORMATS.YMD_SLASH) : ""))
                .map(x -> {
                    MainListProdOrdineProduzioneElencoListModel listModel = new MainListProdOrdineProduzioneElencoListModel();

                    listModel.setOriginalModel(x);

                    listModel.setGroupTitle(x.getRagSocOrd());

                    listModel.setDescription(String.format(getString(R.string.ord_acq_testata), x.getNumero(), UtilityDate.formatDate(x.getDataD(), UtilityDate.COMMONS_DATE_FORMATS.DMY_HUMAN)));

//                    List<MainListProdOrdineProduzioneElencoClienteListModel> clienti = Stream.of(dataList)
//                            .filter(y -> y.getBarcode().equals(x.getBarcode()))
//                            .map(y -> new MainListProdOrdineProduzioneElencoClienteListModel()
//                                    .setPrimaryText(y.getRifOrd())
//                                    .setRightText(y.getCodJcom())
//                                    .setOriginalModel(y))
//                            .toList();

                    MainListProdOrdineProduzioneElencoClienteListModel cliente = new MainListProdOrdineProduzioneElencoClienteListModel()
                            .setPrimaryText(x.getRifOrd())
                            .setRightText(x.getCodJcom())
                            .setOriginalModel(x);

                    listModel.setClientiListModel(Collections.singletonList(cliente));

                    return listModel;
                })
                .toList();
    }


    public void dispatchOrders() {
        List<OrdineAccettazioneInevasoDTO> selectedOrders = Stream.of(this.mOrdiniInevasiMutableData)
                .filter(x -> x.getSelectedObservable().get())
                .flatMap(y -> Stream.of(y.getClientiListModel()).map(MainListProdOrdineProduzioneElencoClienteListModel::getOriginalModel))
                .toList();


        this.mViewModel.loadPicking(selectedOrders);
    }


    @Override
    public void onOrdersDispatched(List<OrdineAccettazioneInevasoDTO> orders, List<SitArtOrdDTO> sitArts) {
        long artsCounter = Stream.of(sitArts)
                .filter(x -> UtilityBigDecimal.greaterThan(x.getQtaDaEvadere(), BigDecimal.ZERO))
                .map(SitArtOrdDTO::getCodMart)
                .distinct()
                .count();

        long ordsCounter = Stream.of(sitArts)
                .distinctBy(x -> x.getDataOrd() + " " + x.getNumOrd() + " " + x.getGestione())
                .count();


        DialogSimpleMessageView.makeInfoDialog(getText(R.string.orders).toString(),
                Html.fromHtml(String.format(getActivity().getResources().getQuantityString(R.plurals.loaded_orders_message, (int) ordsCounter), ordsCounter)
                        + "<br /><br />" +
                        "<b>" + artsCounter + "</b> " + getActivity().getResources().getQuantityString(R.plurals.ordered_articles, (int) artsCounter)),
                null,
                () -> {

                    String cacheSitArtItemID = DataCache.addItem(sitArts);
                    String cacheOrdersItemID = DataCache.addItem(orders);

                    Intent myIntent = new Intent(getActivity(), AccettazioneOrdiniPickingActivity.class);
                    myIntent.putExtra("keyOrders", cacheOrdersItemID);
                    myIntent.putExtra("keySitArts", cacheSitArtItemID);
                    getActivity().startActivity(myIntent);

                }).show(getActivity().getSupportFragmentManager(), "tag");
    }


    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()))
                .toList();

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