package it.integry.integrywmsnative.gest.prod_fabbisogno_linee_prod;

import android.content.Context;
import android.os.Bundle;
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.lifecycle.LiveData;
import androidx.lifecycle.MutableLiveData;

import com.annimon.stream.Stream;
import com.ravikoradiya.liveadapter.LiveAdapter;
import com.ravikoradiya.liveadapter.Type;

import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.Date;
import java.util.List;
import java.util.Objects;

import javax.inject.Inject;

import it.integry.integrywmsnative.BR;
import it.integry.integrywmsnative.MainApplication;
import it.integry.integrywmsnative.R;
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.ITitledFragment;
import it.integry.integrywmsnative.core.model.MtbColr;
import it.integry.integrywmsnative.core.model.secondary.GestioneEnum;
import it.integry.integrywmsnative.core.rest.model.SitArtOrdDTO;
import it.integry.integrywmsnative.core.settings.SettingsManager;
import it.integry.integrywmsnative.core.utility.UtilityBigDecimal;
import it.integry.integrywmsnative.core.utility.UtilityDB;
import it.integry.integrywmsnative.core.utility.UtilityDate;
import it.integry.integrywmsnative.databinding.FragmentProdFabbisognoLineeListSingleItemBinding;
import it.integry.integrywmsnative.databinding.FragmentProdFabbisognoLineeProdBinding;
import it.integry.integrywmsnative.databinding.FragmentProdFabbisognoLineeTitleItemBinding;
import it.integry.integrywmsnative.gest.accettazione_ordini_elenco.dto.OrdineAccettazioneInevasoDTO;
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_fabbisogno_linee_prod.dto.GroupTitleModel;
import it.integry.integrywmsnative.gest.prod_fabbisogno_linee_prod.dto.ProdFabbisognoLineeItemModelDto;
import it.integry.integrywmsnative.gest.prod_fabbisogno_linee_prod.dto.ProdFabbisognoLineeProdDTO;
import it.integry.integrywmsnative.gest.prod_fabbisogno_linee_prod.filters.ProdFabbisognoLineeProdFilterViewModel;
import it.integry.integrywmsnative.gest.prod_versamento_materiale.dto.OrdineLavorazioneDTO;
import it.integry.integrywmsnative.gest.spedizione.SpedizioneActivity;
import it.integry.integrywmsnative.gest.spedizione.dialogs.row_info.prod_fabbisogno_linee_prod.DialogRowInfoProdFabbisognoLineeProdView;
import it.integry.integrywmsnative.ui.filter_chips.FilterChipDTO;
import it.integry.integrywmsnative.ui.filter_chips.FilterChipView;
import it.integry.integrywmsnative.ui.filter_chips.filters.FilterNumeroOrdineLayoutView;

/**
 * A simple {@link Fragment} subclass.
 * Use the {@link ProdFabbisognoLineeProdFragment#newInstance} factory method to
 * create an instance of this fragment.
 */
public class ProdFabbisognoLineeProdFragment extends BaseFragment implements ITitledFragment, ProdFabbisognoLineeProdViewModel.Listener {

    public BindableBoolean fabVisible = new BindableBoolean(false);

    @Inject
    ProdFabbisognoLineeProdViewModel mViewModel;

    private final ArrayList<Runnable> mOnPreDestroyList = new ArrayList<>();
    private final ObservableArrayList<Object> mProdFabbisognoItemModel = new ObservableArrayList<>();
    private FragmentProdFabbisognoLineeProdBinding mBindings;
    private ProdFabbisognoLineeProdFilterViewModel mFilterViewModel = new ProdFabbisognoLineeProdFilterViewModel();

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

    public static ProdFabbisognoLineeProdFragment newInstance() {
        ProdFabbisognoLineeProdFragment fragment = new ProdFabbisognoLineeProdFragment();
        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_fabbisogno_linee_prod, container, false);

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

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

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

        return mBindings.getRoot();
    }

    @Override
    public void onStart() {
        super.onStart();
        mViewModel.init();
    }

    private void initRecyclerView() {
        mViewModel.getOrdiniList().observe(getViewLifecycleOwner(), data -> {
            mBindings.emptyView.setVisibility(data == null || data.isEmpty() ? View.VISIBLE : View.GONE);

            mFilterViewModel.init(mViewModel.getOrdiniList().getValue());
            this.refreshList(null);
        });

        var itemTypeHeader = new Type<GroupTitleModel, FragmentProdFabbisognoLineeTitleItemBinding>(R.layout.fragment_prod_fabbisogno_linee_title_item, BR.item);
        var itemType = new Type<ProdFabbisognoLineeItemModelDto, FragmentProdFabbisognoLineeListSingleItemBinding>(R.layout.fragment_prod_fabbisogno_linee_list_single_item, BR.item);

        itemTypeHeader.onClick(x -> {
            var item = x.getBinding().getItem();
            item.getSelected().set(!item.getSelected().get());

            Stream.of(mProdFabbisognoItemModel)
                    .filter(y -> y instanceof ProdFabbisognoLineeItemModelDto && ((ProdFabbisognoLineeItemModelDto) y).getOrdineLavorazioneDTO().getCodJfas().equals(item.getTitle()))
                    .forEach(y -> {
                        ((ProdFabbisognoLineeItemModelDto) y).getSelected().set(item.selected.get());
                    });

            fabVisible.set(Stream.of(mProdFabbisognoItemModel)
                    .filter(y -> y instanceof ProdFabbisognoLineeItemModelDto)
                    .anyMatch(y -> ((ProdFabbisognoLineeItemModelDto) y).getSelected().get()));

            return null;
        });

        itemType.onClick(x -> {
            var item = x.getBinding().getItem();
            item.getSelected().set(!item.getSelected().get());

            fabVisible.set(Stream.of(mProdFabbisognoItemModel)
                    .filter(y -> y instanceof ProdFabbisognoLineeItemModelDto)
                    .anyMatch(y -> ((ProdFabbisognoLineeItemModelDto) y).getSelected().get()));

            return null;
        });

        new LiveAdapter(mProdFabbisognoItemModel)
                .map(GroupTitleModel.class, itemTypeHeader)
                .map(ProdFabbisognoLineeItemModelDto.class, itemType)
                .into(this.mBindings.inventarioList);
    }

    private void refreshList(List<ProdFabbisognoLineeItemModelDto> filteredList) {
        List<ProdFabbisognoLineeItemModelDto> tmpList;

        if (filteredList != null) {
            tmpList = filteredList;
        } else if (mFilterViewModel != null) {
            mFilterViewModel.applyAllTests();
            tmpList = mFilterViewModel.getCurrentList().getValue();
        } else {
            tmpList = mViewModel.getOrdiniList().getValue();
        }
        this.mProdFabbisognoItemModel.clear();
        if (tmpList != null) {
            this.mProdFabbisognoItemModel.addAll(convertDataModelToListModel(tmpList));
        }
    }

    private List<Object> convertDataModelToListModel(List<ProdFabbisognoLineeItemModelDto> itemModel) {

        Stream.of(itemModel)
                .sorted(Comparator.comparing(x -> x.getOrdineLavorazioneDTO().getCodJfas()))
                .toList();

        List<Object> listaFinale = new ArrayList<>();
        String currentGroup = null;

        for (ProdFabbisognoLineeItemModelDto item : itemModel) {
            OrdineLavorazioneDTO ordineLavorazione = item.getOrdineLavorazioneDTO();
            String codJfas = ordineLavorazione.getCodJfas();

            if (!codJfas.equals(currentGroup)) {
                listaFinale.add(new GroupTitleModel().setTitle(codJfas));
                currentGroup = codJfas;
            }

            listaFinale.add(item);
        }

        return listaFinale;
    }

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

        mFilterViewModel.getCurrentNumOrdsPredicate().addOnPropertyChangedCallback(onPredicateChanged);

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

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

            if (filterChipDTO.getKey() == ProdFabbisognoLineeProdBindings.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));
            }
            this.mBindings.filterChipsGroup.addView(filterChipView);
        }
    }

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

        var filterLayoutView = filterChipDTO
                .getFilterLayoutView();

        if (filterChipDTO.getID() == ProdFabbisognoLineeProdBindings.NUM_ORD_FILTER_ID) {
            ((FilterNumeroOrdineLayoutView) filterLayoutView)
                    .setAllNumOrds(mFilterViewModel.getAllNumOrds())
                    .setAvailableNumOrds(mFilterViewModel.getAvailableNumOrds())
                    .setOnFilterApplied(mFilterViewModel::setNumOrdFilter)
                    .setPreSelectedNumOrds(Stream.of(Objects.requireNonNull(mViewModel.getOrdiniList().getValue()))
                            .filter(mFilterViewModel.getCurrentNumOrdsPredicate().get() == null ?
                                    x -> false : Objects.requireNonNull(mFilterViewModel.getCurrentNumOrdsPredicate().get()))
                            .map(x -> x.getOrdineLavorazioneDTO().getNumOrd())
                            .toList());
        }

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

    }

    @Override
    public void onDestroy() {
        for (Runnable onPreDestroy : mOnPreDestroyList) {
            onPreDestroy.run();
        }

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

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

    public void dispatchOrders() {
        String codMdep = SettingsManager.i().getUserSession().getDepo().getCodMdep();

        String ordini = UtilityDB.listValueToString(Stream.of(mProdFabbisognoItemModel)
                .filter(x -> x instanceof ProdFabbisognoLineeItemModelDto && ((ProdFabbisognoLineeItemModelDto) x).selected.get())
                .map(x -> ((ProdFabbisognoLineeItemModelDto) x).getOrdineLavorazioneDTO().getNumOrd().toString())
                .toList());

        Date dataInizio = Stream.of(mProdFabbisognoItemModel)
                .filter(x -> x instanceof ProdFabbisognoLineeItemModelDto && ((ProdFabbisognoLineeItemModelDto) x).selected.get())
                .map(x -> ((ProdFabbisognoLineeItemModelDto) x).getOrdineLavorazioneDTO().getDataOrdD())
                .min(Date::compareTo)
                .orElse(null);

        Date dataFine = Stream.of(mProdFabbisognoItemModel)
                .filter(x -> x instanceof ProdFabbisognoLineeItemModelDto && ((ProdFabbisognoLineeItemModelDto) x).selected.get())
                .map(x -> ((ProdFabbisognoLineeItemModelDto) x).getOrdineLavorazioneDTO().getDataOrdD())
                .max(Date::compareTo)
                .orElse(null);

        this.mViewModel.loadFabbisogno(ordini, codMdep, dataInizio, dataFine, this::startPickingActivity);

    }

    private void startPickingActivity(List<ProdFabbisognoLineeProdDTO> fabbisognoList) {
        String codMdep = SettingsManager.i().getUserSession().getDepo().getCodMdep();

        List<SitArtOrdDTO> sitArtOrdDTOS = Stream.of(fabbisognoList)
                .map(x -> {
                    SitArtOrdDTO sitArtOrdDTO = new SitArtOrdDTO()
                            .setCodMart(x.getCodMart())
                            .setCodMdep(codMdep)
                            .setQtaOrd(x.getQtaFabbisogno())
                            .setNumCnfOrd(x.getNumCnfFabbisogno())
                            .setQtaCnfOrd(UtilityBigDecimal.divide(x.getQtaFabbisogno(), x.getNumCnfFabbisogno()))
                            .setFlagEnablePickManuale(false)
                            .setCodMgrp(x.getCodMgrp())
                            .setDescrizioneMgrp(x.getDescrizioneMgrp())
                            .setCodMsgr(x.getCodMsgr())
                            .setDescrizioneMsgr(x.getDescrizioneMsgr());

                    sitArtOrdDTO.getExtraInfo().put("dataInizio", x.getDataInizio());
                    sitArtOrdDTO.getExtraInfo().put("dataFine", x.getDataFine());

                    return sitArtOrdDTO;
                })
                .toList();

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

        SpedizioneActivity.startActivity(getActivity(),
                sitArtOrdDTOS,
                new ArrayList<>(),
                new ArrayList<>(),
                GestioneEnum.LAVORAZIONE,
                +1,
                MtbColr.Causale.VERSAMENTO,
                DialogRowInfoProdFabbisognoLineeProdView.class,
                divideByGrpMerc);

    }

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