package it.integry.integrywmsnative.gest.vendita;

import android.app.ProgressDialog;
import android.content.Context;
import android.content.Intent;
import androidx.databinding.DataBindingUtil;
import android.os.Bundle;
import androidx.fragment.app.Fragment;
import androidx.recyclerview.widget.LinearLayoutManager;
import android.text.Html;
import android.text.SpannableString;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;

import com.annimon.stream.Stream;

import java.util.ArrayList;
import java.util.List;

import butterknife.ButterKnife;
import butterknife.OnClick;
import it.integry.integrywmsnative.R;
import it.integry.integrywmsnative.core.REST.CommonRESTException;
import it.integry.integrywmsnative.core.barcode_reader.BarcodeCallbackDTO;
import it.integry.integrywmsnative.core.barcode_reader.BarcodeManager;
import it.integry.integrywmsnative.core.expansion.RunnableArgs;
import it.integry.integrywmsnative.core.interfaces.IFilterableFragment;
import it.integry.integrywmsnative.core.interfaces.IRecyclerFragment;
import it.integry.integrywmsnative.core.interfaces.ISelectAllFragment;
import it.integry.integrywmsnative.core.model.MtbColt;
import it.integry.integrywmsnative.core.settings.SettingsManager;
import it.integry.integrywmsnative.core.utility.UtilityExceptions;
import it.integry.integrywmsnative.core.utility.UtilityToast;
import it.integry.integrywmsnative.databinding.FragmentMainVenditaBinding;
import it.integry.integrywmsnative.core.interfaces.ITitledFragment;
import it.integry.integrywmsnative.gest.picking_libero.PickingLiberoActivity;
import it.integry.integrywmsnative.gest.vendita.core.MainListVenditaAdapter;
import it.integry.integrywmsnative.gest.vendita.core.VenditaHelper;
import it.integry.integrywmsnative.gest.vendita.dialogs.DialogVenditaFiltroAvanzato;
import it.integry.integrywmsnative.gest.vendita.dialogs.DialogVenditaFiltroAvanzatoViewModel;
import it.integry.integrywmsnative.gest.vendita.dto.OrdineVenditaGroupedInevasoDTO;
import it.integry.integrywmsnative.gest.vendita.dto.OrdineVenditaInevasoDTO;
import it.integry.integrywmsnative.gest.vendita.dto.PickingObjectDTO;
import it.integry.integrywmsnative.gest.vendita.viewmodel.VenditaViewModel;
import it.integry.integrywmsnative.gest.vendita_ordine_inevaso.VenditaOrdineInevasoActivity;
import it.integry.integrywmsnative.view.dialogs.DialogSimpleMessageHelper;
import it.integry.plugins.waterfalltoolbar.WaterfallToolbar;

public class MainVenditaFragment extends Fragment implements ITitledFragment, IRecyclerFragment, ISelectAllFragment, IFilterableFragment {

    private static WaterfallToolbar mWaterfallToolbar;

    private VenditaHelper mHelper;
    private FragmentMainVenditaBinding mBinding = null;
    private VenditaViewModel mViewModel;

    private MainListVenditaAdapter mAdapter;

    private List<OrdineVenditaInevasoDTO> mOriginalOrderList;
    private List<OrdineVenditaGroupedInevasoDTO> groupedOrdiniInevasi;

    private DialogVenditaFiltroAvanzatoViewModel mAppliedFilterViewModel;

    private int barcodeScannerIstanceID = -1;



    public MainVenditaFragment() {

    }

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

    @Override
    public String getTitle(Context context){
        return context.getText(R.string.vendita_title_fragment).toString();
    }

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        if (getArguments() != null) {
        }

        setHasOptionsMenu(true);

        init();
    }


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

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

        mBinding = DataBindingUtil.inflate(inflater, R.layout.fragment_main_vendita, container, false);

        mBinding.setView(this);
        mBinding.venditaMainList.setLayoutManager(new LinearLayoutManager(getActivity()));
        mBinding.venditaMainFab.hide();

        ButterKnife.bind(this, mBinding.getRoot());

        mWaterfallToolbar.setRecyclerView(mBinding.venditaMainList);

        return mBinding.getRoot();
    }

    @Override
    public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
        inflater.inflate(R.menu.fragment_vendita, menu);
        super.onCreateOptionsMenu(menu, inflater);
    }

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {

        if(item.getItemId() == R.id.action_free_picking) {
            Intent myIntent = new Intent(getActivity(), PickingLiberoActivity.class);
            startActivity(myIntent);
        }

        return true;

    }


    private void init(){

        final ProgressDialog progress = ProgressDialog.show(getActivity(), getText(R.string.waiting),
                getText(R.string.loading) + " ...", true);

        mHelper = new VenditaHelper(getActivity());
        mViewModel = new VenditaViewModel(getActivity(), this, mBinding, mHelper);

        mHelper.loadOrdini(new VenditaHelper.ILoadOrdiniCallback() {
            @Override
            public void onLoadSuccess(List<OrdineVenditaInevasoDTO> ordini) {
                UtilityToast.showToast("Caricati " + ordini.size() + " ordini");
                mOriginalOrderList = ordini;
                mViewModel.setListOrder(ordini);

                groupOrdini(ordini);
                initRecyclerView();
                progress.dismiss();
            }

            @Override
            public void onLoadFail(Exception ex) {
                mOriginalOrderList = new ArrayList<>();
                progress.dismiss();

                String errorMessage = CommonRESTException.tryRecognizeThenGetMessage(ex);
                if(errorMessage == null) errorMessage = ex.getMessage();
                DialogSimpleMessageHelper.makeErrorDialog(getActivity(), new SpannableString(errorMessage), null, null).show();
            }
        });

        barcodeScannerIstanceID = BarcodeManager.addCallback(new BarcodeCallbackDTO()
                .setOnScanSuccessfull(mViewModel.onScanSuccessfull)
                .setOnScanFailed(ex -> UtilityExceptions.defaultException(getActivity(), ex, false)));
    }


    public void groupOrdini(List<OrdineVenditaInevasoDTO> ordini){

        groupedOrdiniInevasi = new ArrayList<>();

        //Splitto gli ordini per codAnagOrd (Cliente)
        Stream.of(ordini)
                .distinctBy(OrdineVenditaInevasoDTO::getCodAnagOrd)
                .sortBy(OrdineVenditaInevasoDTO::getRagSocOrd)
                .map(x -> x.getCodAnagOrd() + "#_#" + x.getRagSocOrd())
                .forEach(anagOrd -> {

                    String codAnagOrd = anagOrd.substring(0, anagOrd.indexOf("#_#"));
                    String ragSocOrd = anagOrd.substring(anagOrd.indexOf("#_#") + 3, anagOrd.length());

                    OrdineVenditaGroupedInevasoDTO groupedOrdine = new OrdineVenditaGroupedInevasoDTO();

                    groupedOrdine.codAnagClie = codAnagOrd;
                    groupedOrdine.nomeCliente = ragSocOrd;
                    groupedOrdine.ordini = new ArrayList<>();


                    //Raggruppo gli ordini del singolo fornitore suddivisi per data, dataCons e numero
                    Stream.of(ordini)
                            .filter(x -> x.getCodAnagOrd().equalsIgnoreCase(codAnagOrd))
                            .distinctBy(x -> x.getDataOrdS() + " - " + x.getDataConsS() + " - " + x.getNumOrd())
                            .forEach(ord -> {


                                OrdineVenditaGroupedInevasoDTO.Ordine rigaOrdine = new OrdineVenditaGroupedInevasoDTO.Ordine();

                                rigaOrdine
                                    .setData(ord.getDataOrdS())
                                    .setNumero(ord.getNumOrd())
                                    .setCodAnagOrd(ord.getCodAnagOrd())
                                    .setRagSocOrd(ord.getRagSocOrd())
                                    .setPesoTotale(ord.getPesoTotale() != null ? ord.getPesoTotale().floatValue() : null)
                                    .setBarcode(ord.getBarcode())
                                    .setTermCons(ord.getTermCons())
                                    .setDataCons(ord.getDataConsS())
                                    .setRifOrd(ord.getRifOrd())
                                    .setGestione(ord.getGestione());

                                rigaOrdine.clienti = new ArrayList<>();


                                //Leggo tutti i clienti dell'ordine corrente
                                Stream.of(ordini)
                                        .filter(x ->    x.getCodAnagOrd().equalsIgnoreCase(codAnagOrd) &&
                                                        x.getNumOrd().equals(ord.getNumOrd()) &&
                                                        x.getDataOrdS().equalsIgnoreCase(ord.getDataOrdS()) &&
                                                        x.getDataConsS().equalsIgnoreCase(ord.getDataConsS()))
                                        .distinctBy(OrdineVenditaInevasoDTO::getCodJcom)
                                        .forEach(ordCliente -> {

                                            OrdineVenditaGroupedInevasoDTO.Cliente cliente = new OrdineVenditaGroupedInevasoDTO.Cliente();

                                            cliente.codJcom = ordCliente.getCodJcom();
                                            cliente.ragSocCom = ordCliente.getRagSocCom();
                                            cliente.descrCom = ordCliente.getDescrizioneCom();
                                            cliente.dataCons = ordCliente.getDataConsS();
                                            cliente.numCnf = ordCliente.getNumCnfdaEvadere() != null ? ordCliente.getNumCnfdaEvadere().floatValue() : 0;
                                            cliente.rifOrd = ordCliente.getRifOrd();

                                            rigaOrdine.clienti.add(cliente);

                                        });

                                groupedOrdine.ordini.add(rigaOrdine);


                            });

                    groupedOrdiniInevasi.add(groupedOrdine);

                });


    }

    private void initRecyclerView() {
        mAdapter = new MainListVenditaAdapter(getActivity(), groupedOrdiniInevasi, onGroupSelectionChanged);
        mBinding.venditaMainList.setAdapter(mAdapter);
    }

    public void refreshRecyclerView() {
        mAdapter.updateItems(groupedOrdiniInevasi);
    }

    RunnableArgs<OrdineVenditaGroupedInevasoDTO> onGroupSelectionChanged = dto -> {
        List<OrdineVenditaGroupedInevasoDTO> selectedOrders = mHelper.getSelectedOrders(groupedOrdiniInevasi);

        if(!SettingsManager.iDB().isFlagMultiClienteOrdV()){

            if(selectedOrders != null && selectedOrders.size() > 1){
                for (OrdineVenditaGroupedInevasoDTO selectedOrder : selectedOrders) {
                    if(!dto.codAnagClie.equalsIgnoreCase(selectedOrder.codAnagClie)) {
                        Stream.of(selectedOrder.ordini).forEach(x -> x.setCheckbox(false));
                    }
                }
            }
        }

        if(selectedOrders != null && selectedOrders.size() > 0) mBinding.venditaMainFab.show();
        else mBinding.venditaMainFab.hide();
    };


    @OnClick(R.id.vendita_main_fab)
    public void onClick(View view) {

        List<OrdineVenditaGroupedInevasoDTO> selectedOrders = mHelper.getSelectedOrders(groupedOrdiniInevasi);
        List<String> barcodes = new ArrayList<>();

        String dataCons = null;

        for(OrdineVenditaGroupedInevasoDTO ordine : selectedOrders){
            for(OrdineVenditaGroupedInevasoDTO.Ordine righeOrd : ordine.ordini){
                if(!barcodes.contains(righeOrd.getBarcode())) barcodes.add(righeOrd.getBarcode());

                if(dataCons == null) dataCons = righeOrd.getDataConsS();
                else if(!dataCons.equalsIgnoreCase(righeOrd.getDataConsS())) dataCons = "";
            }
        }

        final ProgressDialog progress = ProgressDialog.show(getActivity(), getText(R.string.waiting),
                getText(R.string.loading) + " ...", true);

        mHelper.retrievePickingList(barcodes, dataCons, new VenditaHelper.ILoadPickingListCallback() {
            @Override
            public void onLoadSuccess(final List<PickingObjectDTO> ordini) {


                mHelper.getBancaliVenditaGiaRegistrati(selectedOrders, mtbColtList -> {

                    progress.dismiss();

                    List<String> codMarts = Stream.of(ordini)
                            .distinctBy(PickingObjectDTO::getCodMart)
                            .map(PickingObjectDTO::getCodMart)
                            .toList();

                    int alreadyRegisteredUL = mtbColtList.size();

                    DialogSimpleMessageHelper.makeInfoDialog(getActivity(),
                            getText(R.string.orders).toString(),
                            Html.fromHtml(String.format(getActivity().getResources().getQuantityString(R.plurals.loaded_orders_message, barcodes.size()), barcodes.size())
                                    + "<br />" +
                                    "<b>" + codMarts.size() + "</b> " + getActivity().getResources().getQuantityString(R.plurals.available_articles, codMarts.size())
                                    + "<br />" +
                                    "<b>" + alreadyRegisteredUL + "</b> " + getActivity().getResources().getQuantityString(R.plurals.already_registered_lu, alreadyRegisteredUL)),
                            null,
                            () -> {

                                Intent myIntent = new Intent(getActivity(), VenditaOrdineInevasoActivity.class);
                                myIntent.putExtra("keyPickingList", (ArrayList<PickingObjectDTO>) ordini); //Optional parameters
                                myIntent.putExtra("keyTestateOrdini", (ArrayList<OrdineVenditaGroupedInevasoDTO>)selectedOrders);
                                myIntent.putExtra("keyColliRegistrati", (ArrayList<MtbColt>)mtbColtList);
                                getActivity().startActivity(myIntent);

                            }).show();

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

            }

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


    }



    @Override
    public void setWaterfallToolbar(WaterfallToolbar waterfallToolbar) {
        mWaterfallToolbar = waterfallToolbar;
    }

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

    @Override
    public void onSelectAll() {
        if(groupedOrdiniInevasi != null && groupedOrdiniInevasi.size() > 0) {
            if(mHelper.getSelectedOrders(groupedOrdiniInevasi).size() > 0){
                mHelper.deselectAll(groupedOrdiniInevasi);
            } else {
                //Selezionare solo quelli attualmente a video
                mHelper.selectAll(groupedOrdiniInevasi);
            }

        }
    }

    @Override
    public void onFilterClick() {

        DialogVenditaFiltroAvanzato.make(getActivity(), mOriginalOrderList, mAppliedFilterViewModel, (filteredOrderList, filter) -> {

            mAppliedFilterViewModel = filter;

            if(filteredOrderList != null){

                groupOrdini(filteredOrderList);
                refreshRecyclerView();
            }

        }).show();

    }
}
