package it.integry.integrywmsnative.view.dialogs.choose_arts_from_mtbcolr_list;

import android.app.Dialog;
import android.content.Context;
import android.content.DialogInterface;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;

import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.appcompat.widget.SearchView;
import androidx.lifecycle.MutableLiveData;

import com.annimon.stream.Stream;
import com.google.android.material.dialog.MaterialAlertDialogBuilder;
import com.ravikoradiya.liveadapter.LiveAdapter;

import java.util.List;

import javax.inject.Inject;

import it.integry.barcode_base_android_library.model.BarcodeScanDTO;
import it.integry.integrywmsnative.BR;
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.expansion.BaseDialogFragment;
import it.integry.integrywmsnative.core.expansion.RunnableArgs;
import it.integry.integrywmsnative.core.model.MtbAart;
import it.integry.integrywmsnative.core.model.MtbColr;
import it.integry.integrywmsnative.core.rest.consumers.ArticoloRESTConsumer;
import it.integry.integrywmsnative.core.rest.consumers.BarcodeRESTConsumer;
import it.integry.integrywmsnative.core.rest.model.Ean128Model;
import it.integry.integrywmsnative.core.utility.UtilityBarcode;
import it.integry.integrywmsnative.core.utility.UtilityExceptions;
import it.integry.integrywmsnative.core.utility.UtilityString;
import it.integry.integrywmsnative.databinding.DialogChooseArtsFromMtbColrListLayoutBinding;
import it.integry.integrywmsnative.view.dialogs.DialogCommon;
import kotlin.Unit;

public class DialogChooseArtsFromMtbColrList extends BaseDialogFragment implements DialogInterface.OnShowListener {

    @Inject
    DialogChooseArtsFromMtbColrListViewModel mViewModel;
    @Inject
    BarcodeRESTConsumer barcodeRESTConsumer;
    @Inject
    ArticoloRESTConsumer articoloRESTConsumer;


    private int mBarcodeScannerIstanceID;
    private final List<MtbColr> inputMtbColrList;
    private MtbAart selectedArt;
    private final RunnableArgs<List<MtbColr>> onConfirmed;
    private final Runnable onAbort;


    private DialogChooseArtsFromMtbColrListLayoutBinding mBindings;

    private List<DialogChooseArtsFromMtbColrListItemModel> mtbColrItemModels;
    private final MutableLiveData<List<DialogChooseArtsFromMtbColrListItemModel>> hiddenMtbColrItemModels = new MutableLiveData<>();
    private Context mContext;

    public static DialogChooseArtsFromMtbColrList newInstance(List<MtbColr> listaMtbColr, RunnableArgs<List<MtbColr>> onItemsChoosed, Runnable onAbort) {
        return new DialogChooseArtsFromMtbColrList(listaMtbColr, onItemsChoosed, onAbort);
    }

    public static DialogChooseArtsFromMtbColrList newInstance(List<MtbColr> listaMtbColr, MtbAart mtbAart, RunnableArgs<List<MtbColr>> onItemsChoosed, Runnable onAbort) {
        DialogChooseArtsFromMtbColrList dialog = newInstance(listaMtbColr, onItemsChoosed, onAbort);
        dialog.setSelectedArt(mtbAart);
        return dialog;
    }

    public void setSelectedArt(MtbAart mtbAart) {
        this.selectedArt = mtbAart;
    }

    private DialogChooseArtsFromMtbColrList(List<MtbColr> listaMtbColr, RunnableArgs<List<MtbColr>> onConfirmed, Runnable onAbort) {
        super();

        this.inputMtbColrList = listaMtbColr;

        this.onConfirmed = onConfirmed;
        this.onAbort = onAbort;

//        mDataset = new ArrayList<>();

//        if (listaMtbColr != null) {
//            for (MtbColr mtbColr : listaMtbColr) {
//                if (UtilityString.isNullOrEmpty(mtbColr.getUntMis()) && mtbColr.getMtbAart() != null) {
//                    mtbColr.setUntMis(mtbColr.getMtbAart().getUntMis());
//                }
//
//                mDataset.add(new DialogChooseArtsFromMtbColrListItemModel().setMtbColr(mtbColr));
//            }
//        }
    }

    @NonNull
    @Override
    public Dialog onCreateDialog(@Nullable Bundle savedInstanceState) {
        this.mContext = requireContext();

        mBindings = DialogChooseArtsFromMtbColrListLayoutBinding.inflate(LayoutInflater.from(this.mContext), null, false);
        mBindings.setLifecycleOwner(this);

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

        var cancelable = false;

        var alertDialog = new MaterialAlertDialogBuilder(this.mContext)
                .setView(mBindings.getRoot())
                .setCancelable(cancelable)
                .setPositiveButton(R.string.ok, (dialog, which) -> {
                    var selectedArts = Stream.of(this.mtbColrItemModels)
                            .filter(x -> x.getChecked().get())
                            .map(DialogChooseArtsFromMtbColrListItemModel::getMtbColr)
                            .toList();

                    if (selectedArts.isEmpty()) {
                        if (this.onAbort != null) this.onAbort.run();
                        return;
                    }

                    if (this.onConfirmed != null)
                        this.onConfirmed.run(selectedArts);
                })
                .setNegativeButton(R.string.abort, (dialog, which) -> {
                    if (this.onAbort != null) this.onAbort.run();
                })
                .create();


        alertDialog.setOnShowListener(this);
        alertDialog.setCanceledOnTouchOutside(cancelable);
        return alertDialog;
    }


    @Override
    public void onShow(DialogInterface dialogInterface) {
        this.initList();
        this.initFilter();
        this.setupBarcode();

        if (selectedArt != null) {
            this.loadArticolo(selectedArt.getBarCode(), null);
        }
    }

    private void initList() {
        mBindings.listaArts.setHasFixedSize(true);

        this.mtbColrItemModels = Stream.of(this.inputMtbColrList)
                .map(x -> new DialogChooseArtsFromMtbColrListItemModel()
                        .setMtbColr(x))
                .toList();

        this.hiddenMtbColrItemModels.setValue(this.mtbColrItemModels);

        new LiveAdapter(this.hiddenMtbColrItemModels, this, BR.item)
                .map(DialogChooseArtsFromMtbColrListItemModel.class, R.layout.dialog_choose_arts_from_mtb_colr_list__item_model)
                .onNoData(noData -> {
                    mBindings.emptyView.setVisibility(noData ? View.VISIBLE : View.GONE);
                    return Unit.INSTANCE;
                })
                .into(this.mBindings.listaArts);
    }


    private void initFilter() {
        mBindings.mainSearch.setOnCloseListener(() -> {
            this.removeListFilter();
            return true;
        });

        mBindings.mainSearch.setOnQueryTextListener(new SearchView.OnQueryTextListener() {
            @Override
            public boolean onQueryTextSubmit(String query) {
                return true;
            }

            @Override
            public boolean onQueryTextChange(String newText) {
                newText = newText.toLowerCase();

                String finalNewText = newText;
                final List<DialogChooseArtsFromMtbColrListItemModel> filtered = Stream.of(mtbColrItemModels)
                        .filter(x -> {
                            String codMart = x.getMtbColr().getMtbAart().getCodMart().toLowerCase();
                            String descrizioneArt = x.getMtbColr().getMtbAart().getDescrizioneEstesa().toLowerCase();
                            String diacod = x.getMtbColr().getMtbAart().getDiacod();
                            if (!UtilityString.isNullOrEmpty(diacod)) {
                                diacod = diacod.toLowerCase();
                            }

                            return ((codMart.startsWith(finalNewText) ||
                                    codMart.endsWith(finalNewText) ||
                                    codMart.contains(finalNewText) ||
                                    codMart.equalsIgnoreCase(finalNewText)) ||
                                    (descrizioneArt.startsWith(finalNewText) ||
                                            descrizioneArt.endsWith(finalNewText) ||
                                            descrizioneArt.contains(finalNewText) ||
                                            descrizioneArt.equalsIgnoreCase(finalNewText)) ||
                                    (!UtilityString.isNullOrEmpty(diacod) && (diacod.startsWith(finalNewText) ||
                                            diacod.endsWith(finalNewText) ||
                                            diacod.contains(finalNewText) ||
                                            diacod.equalsIgnoreCase(finalNewText))));
                        })
                        .toList();

                hiddenMtbColrItemModels.postValue(filtered);
                return true;
            }
        });
    }

    private void removeListFilter() {
        for (DialogChooseArtsFromMtbColrListItemModel itemModel : mtbColrItemModels) {
            itemModel.setHidden(false);
        }
    }

    private void setupBarcode() {
        BarcodeManager.enable();

        mBarcodeScannerIstanceID = BarcodeManager.addCallback(new BarcodeCallbackDTO()
                .setOnScanSuccessful(onScanSuccessfull)
                .setOnScanFailed(ex -> UtilityExceptions.defaultException(mContext, ex, false)));
    }


    @Override
    public void onDismiss(@NonNull DialogInterface dialog) {
        BarcodeManager.removeCallback(mBarcodeScannerIstanceID);
        this.onAbort.run();
        super.onDismiss(dialog);
    }


    private final RunnableArgs<BarcodeScanDTO> onScanSuccessfull = data -> {
        onLoadingStarted();


        if (UtilityBarcode.isEan13(data)) {
            this.loadArticolo(data.getStringValue(), null);
        } else if (UtilityBarcode.isEtichetta128(data)) {
            this.executeEtichettaEan128(data);
        } else {
            onLoadingEnded();
        }


    };


    private void executeEtichettaEan128(BarcodeScanDTO barcodeScanDTO) {
        this.barcodeRESTConsumer.decodeEan128(barcodeScanDTO, ean128Model -> {

            String barcodeProd = null;

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


            if (!UtilityString.isNullOrEmpty(barcodeProd)) {

                if (!UtilityString.isNullOrEmpty(ean128Model.Gtin) || !UtilityString.isNullOrEmpty(ean128Model.Content)) {
                    this.loadArticolo(barcodeProd, ean128Model);
                } else {
                    DialogCommon.showNoArtFoundDialog(mContext, this::onLoadingEnded);

                }


            } else {
                //EAN 128 non completo o comunque mancano i riferimenti al prodotto
                DialogCommon.showNoArtFoundDialog(mContext, this::onLoadingEnded);

            }
        }, this::onError);
    }


    private void loadArticolo(String barcodeProd, Ean128Model ean128Model) {
        this.articoloRESTConsumer.getByBarcodeProd(barcodeProd, mtbAartList -> {

            if (mtbAartList != null && mtbAartList.size() > 0) {
                this.mBindings.mainSearch.setQuery(barcodeProd, false);

                this.searchArtInList(mtbAartList.get(0), ean128Model);

                onLoadingEnded();

            } else {

                DialogCommon.showNoArtFoundDialog(mContext, this::onLoadingEnded);
            }

        }, this::onError);
    }


    private void searchArtInList(MtbAart mtbAart, Ean128Model ean128Model) {
        removeListFilter();

        List<DialogChooseArtsFromMtbColrListItemModel> foundRowsList = Stream.of(mtbColrItemModels)
                .filter(x -> x.getMtbColr().getMtbAart().getCodMart().equalsIgnoreCase(mtbAart.getCodMart()) &&
                        !x.isHidden())
                .toList();

        if (foundRowsList.size() == 0) {
            DialogCommon.showNoArtFoundDialog(mContext, null);
        } else {

            for (int i = 0; i < mtbColrItemModels.size(); i++) {
                mtbColrItemModels.get(i).setHidden(!foundRowsList.contains(mtbColrItemModels.get(i)));
            }
        }
    }


}
