package it.integry.integrywmsnative.gest.versamento_merce.viewmodel;

import android.app.Activity;
import android.app.ProgressDialog;
import android.content.Context;
import androidx.databinding.ObservableArrayList;
import androidx.databinding.ObservableField;
import android.text.Html;
import android.text.SpannableString;

import com.annimon.stream.Stream;

import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Date;
import java.util.Iterator;
import java.util.List;

import it.integry.integrywmsnative.MainActivity;
import it.integry.integrywmsnative.R;
import it.integry.integrywmsnative.core.REST.consumers.BarcodeRESTConsumer;
import it.integry.integrywmsnative.core.REST.consumers.ColliMagazzinoRESTConsumer;
import it.integry.integrywmsnative.core.REST.consumers.PosizioneRESTonsumer;
import it.integry.integrywmsnative.core.barcode_reader.BarcodeManager;
import it.integry.integrywmsnative.core.expansion.RunnableArgs;
import it.integry.integrywmsnative.core.model.CommonModelConsts;
import it.integry.integrywmsnative.core.model.MtbColr;
import it.integry.integrywmsnative.core.model.MtbColt;
import it.integry.integrywmsnative.core.model.MtbDepoPosizione;
import it.integry.integrywmsnative.core.model.secondary.GestioneEnum;
import it.integry.integrywmsnative.core.settings.SettingsManager;
import it.integry.integrywmsnative.core.utility.UtilityBarcode;
import it.integry.integrywmsnative.core.utility.UtilityExceptions;
import it.integry.integrywmsnative.core.utility.UtilityPosizione;
import it.integry.integrywmsnative.core.utility.UtilityProgress;
import it.integry.integrywmsnative.core.utility.UtilityString;
import it.integry.integrywmsnative.databinding.FragmentMainVersamentoMerceBinding;
import it.integry.integrywmsnative.gest.versamento_merce.core.VersamentoMerceHelper;
import it.integry.integrywmsnative.view.dialogs.DialogAskLivelloPosizione;
import it.integry.integrywmsnative.view.dialogs.DialogSimpleMessageHelper;
import it.integry.integrywmsnative.view.dialogs.choose_arts_from_lista_arts.DialogChooseArtsFromListaArts;
import it.integry.integrywmsnative.view.dialogs.input_quantity.DialogInputQuantity;
import it.integry.integrywmsnative.view.dialogs.scan_or_create_lu.DialogScanOrCreateLU;
import it.integry.plugins.barcode_base_library.model.BarcodeScanDTO;
import it.integry.plugins.barcode_base_library.model.BarcodeType;

public class VersamentoMerceViewModel {


    private Context mContext;
    private FragmentMainVersamentoMerceBinding mBinding;
    private VersamentoMerceHelper mHelper;

    public ObservableField<MtbColt> mtbColt = new ObservableField<>();

    public void init(Activity context, FragmentMainVersamentoMerceBinding binding, VersamentoMerceHelper helper) {
        mContext = context;
        mBinding = binding;
        mHelper = helper;
    }

    public void openLU() {
        DialogScanOrCreateLU.make(mContext, true, mtbColt -> {
            if(mtbColt == null) {
                ((MainActivity)mContext).popToMain();
            } else if((mtbColt.getGestioneEnum() == GestioneEnum.ACQUISTO || mtbColt.getGestioneEnum() == GestioneEnum.LAVORAZIONE) && mtbColt.getSegno().equals(+1)){
                setMtbColt(mtbColt);
            } else {
                DialogSimpleMessageHelper.makeWarningDialog(mContext,
                        new SpannableString(Html.fromHtml("Sono accettate solamente UL di <b>Acquisto</b> o <b>Lavorazione</b> di <b>CARICO</b>")),
                        null, this::openLU).show();
            }
        }).show();
    }

    public void setMtbColt(MtbColt mtbColt) {
        this.mtbColt.set(mtbColt);
    }

    public void resetMtbColt() {
        this.mtbColt.set(null);
        openLU();
    }

    public RunnableArgs<BarcodeScanDTO> onScanSuccessfull = data -> {

        BarcodeManager.disable();

        ProgressDialog progressDialog = UtilityProgress.createDefaultProgressDialog(mContext);

        if(UtilityBarcode.isEtichettaPosizione(data)){
            progressDialog.show();
            this.executeEtichettaPosizione(data, progressDialog);
        } else if(data.getType() == BarcodeType.EAN8 || data.getType() == BarcodeType.EAN13 || data.getType() == BarcodeType.UPCA){
            //searchArtInt(data.getStringValue());
        } else if(UtilityBarcode.isEtichettaAnonima(data)) {
            this.executeEtichettaLU(data.getStringValue(), true,  progressDialog);
        }else if(UtilityBarcode.isEtichetta128(data)) {
            this.executeEtichettaEan128(data, progressDialog);
        } else {
            BarcodeManager.enable();
        }


    };

    private void executeEtichettaPosizione(BarcodeScanDTO barcodeScanDTO, ProgressDialog progressDialog) {
        MtbDepoPosizione foundPosizione = Stream.of(SettingsManager.iDB().getAvailablePosizioni())
                .filter(x -> x.getPosizione().equalsIgnoreCase(barcodeScanDTO.getStringValue()))
                .single();

        if(foundPosizione.isFlagMonoCollo()) {

            PosizioneRESTonsumer.getBancaliInPosizione(foundPosizione, mtbColtList -> {

                if(mtbColtList == null || mtbColtList.size() == 0){
                    progressDialog.dismiss();
                    BarcodeManager.enable();
                    showNoULFound();
                } else if (mtbColtList.size() == 1) {
                    ColliMagazzinoRESTConsumer.getByTestata(mtbColtList.get(0), true, false, mtbColt -> {

                        //TAKE HERE
                        pickMerceULtoUL(mtbColt, progressDialog);

                    }, ex ->  {
                        UtilityExceptions.defaultException(mContext, ex, progressDialog);
                        BarcodeManager.enable();
                    });
                }

            }, ex -> {
                UtilityExceptions.defaultException(mContext, ex, progressDialog);
                BarcodeManager.enable();
            });
        } else {
            updatePosizione(foundPosizione, UtilityPosizione.isPosizioneWithLivello(foundPosizione), progressDialog);
        }
    }

    private void executeEtichettaEan128(BarcodeScanDTO barcodeScanDTO, ProgressDialog progressDialog) {
        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.Sscc)){
                    this.executeEtichettaLU(ean128Model.Sscc, false, progressDialog);
                } else {
                    showNoULFound();
                    progressDialog.dismiss();
                    BarcodeManager.enable();
                }


            } else {
                //EAN 128 non completo o comunque mancano i riferimenti al prodotto
                progressDialog.dismiss();
                BarcodeManager.enable();
            }
        }, ex-> {
            UtilityExceptions.defaultException(mContext, ex, progressDialog);
            BarcodeManager.enable();
        });
    }




    private void executeEtichettaLU(String sscc, boolean isAnonima, ProgressDialog progressDialog) {
        ColliMagazzinoRESTConsumer.getBySSCC(sscc, true, false, mtbColt -> {

            if(mtbColt == null && !isAnonima) {
                showNoULFound();
                BarcodeManager.enable();
                progressDialog.dismiss();
            } else if(mtbColt != null && (mtbColt.getGestioneEnum() == GestioneEnum.ACQUISTO || mtbColt.getGestioneEnum() == GestioneEnum.VENDITA)) {
                showWrongGestioneUL();
                BarcodeManager.enable();
                progressDialog.dismiss();
            } else {
                if(mtbColt == null && isAnonima) {
                    ColliMagazzinoRESTConsumer.createColloFromEtichettaAnonima(sscc, GestioneEnum.LAVORAZIONE, mtbColtAnonimo -> {
                        pickMerceULtoUL(mtbColtAnonimo, progressDialog);
                    }, ex -> {
                        UtilityExceptions.defaultException(mContext, ex, progressDialog);
                        BarcodeManager.enable();
                    });

                } else {
                    pickMerceULtoUL(mtbColt, progressDialog);
                }


            }


        }, ex ->  {
            UtilityExceptions.defaultException(mContext, ex, progressDialog);
            BarcodeManager.enable();
        });
    }

    private void updatePosizione(MtbDepoPosizione mtbDepoPosizione, boolean shouldAskLivello, ProgressDialog progressDialog) {

        if(shouldAskLivello) {
            DialogAskLivelloPosizione.make(mContext, mtbDepoPosizione, false, newPosizione -> {

                if(newPosizione == null) {
                    updatePosizione(mtbDepoPosizione, shouldAskLivello, progressDialog);
                } else {
                    updatePosizione(newPosizione, false, progressDialog);
                }

            }, ex -> {
                UtilityExceptions.defaultException(mContext, ex, progressDialog);
                BarcodeManager.enable();
            });
        } else {
            ColliMagazzinoRESTConsumer.changePosizione(mtbColt.get(), mtbDepoPosizione, () -> {
                progressDialog.dismiss();
                BarcodeManager.enable();

                showDataSavedDialog();
            }, ex -> {
                UtilityExceptions.defaultException(mContext, ex, progressDialog);
                BarcodeManager.enable();
            });
        }

    }


    private void pickMerceULtoUL(MtbColt destMtbColt, ProgressDialog progressDialog) {
        List<MtbColr> mtbColrsToPick = Stream.of(mtbColt.get().getMtbColr())
                .filter(x -> x.getQtaCol().floatValue() > 0)
                .toList();

        DialogChooseArtsFromListaArts.make(mContext, mtbColrsToPick, pickedAarts -> {

            progressDialog.dismiss();

            List<MtbColr> destNewMtbColr = new ArrayList<>();

            askQuantities(pickedAarts.iterator(), destNewMtbColr, () -> {
                BarcodeManager.enable();

                if(destNewMtbColr != null && destNewMtbColr.size() > 0){
                    MtbColt clonedTestata = (MtbColt) destMtbColt.clone();
                    ObservableArrayList<MtbColr> mtbColrObservableField = new ObservableArrayList<>();

                    for(int i = 0; i < destNewMtbColr.size(); i++) {
                        MtbColr cloneMtbColr = (MtbColr) destNewMtbColr.get(i).clone();

                        cloneMtbColr
                                .setGestioneRif(cloneMtbColr.getGestione())
                                .setGestione(null);

                        cloneMtbColr
                                .setSerColloRif(cloneMtbColr.getSerCollo())
                                .setSerCollo(null);

                        cloneMtbColr
                                .setNumColloRif(cloneMtbColr.getNumCollo())
                                .setNumCollo(null);

                        cloneMtbColr
                                .setDataColloRif(cloneMtbColr.getDataColloS())
                                .setDataCollo(null);

                        mtbColrObservableField.add(cloneMtbColr);
                    }

                    clonedTestata.setMtbColr(mtbColrObservableField);

                    saveLU(clonedTestata);
                }

            });

        }, () -> {
            progressDialog.dismiss();
            BarcodeManager.enable();
        }).show();
    }


    private void askQuantities(Iterator<MtbColr> sourceMtbColrs, List<MtbColr> destMtbColr, Runnable onComplete){

        if(sourceMtbColrs.hasNext()){

            askSingleQuantity(sourceMtbColrs.next(), mtbColr -> {


                destMtbColr.add(mtbColr);
                askQuantities(sourceMtbColrs, destMtbColr, onComplete);
            });
        } else {
            onComplete.run();
        }
    }


    private void askSingleQuantity(MtbColr mtbColr, RunnableArgs<MtbColr> onComplete) {
        DialogInputQuantity.DTO dto = new DialogInputQuantity.DTO()
                .setBatchLot(mtbColr.getPartitaMag())
                .setDataScad(mtbColr.getDataScadPartitaD())
                .setMtbAart(mtbColr.getMtbAart())
                .setQtaTot(mtbColr.getQtaCol())
                .setQtaOrd(mtbColr.getQtaCol())
                .setQtaDaEvadere(new BigDecimal(-1))
                .setQtaEvasa(BigDecimal.ZERO)
                .setCanPartitaMagBeChanged(false)
                .setCanDataScadBeChanged(false)
                .setMaxQta(mtbColr.getQtaCol());

        DialogInputQuantity.makeBase(mContext, dto, false, quantityDTO -> {
            mtbColr
                    .setQtaCol(new BigDecimal(quantityDTO.qtaTot.get()))
                    .setQtaCnf(new BigDecimal(quantityDTO.qtaCnf.get()))
                    .setNumCnf(new BigDecimal(quantityDTO.numCnf.get()))
                    .setDatetimeRow(new Date());

            onComplete.run(mtbColr);
        }).show();
    }


    private void showNoULFound() {
        DialogSimpleMessageHelper.makeWarningDialog(mContext,
                new SpannableString(mContext.getResources().getText(R.string.no_lu_found_message)),
                null, null).show();
    }


    private void showWrongGestioneUL() {
        DialogSimpleMessageHelper.makeWarningDialog(mContext,
                new SpannableString(Html.fromHtml(mContext.getResources().getText(R.string.gestione_A_V_not_accepted_message).toString())),
                null, null).show();
    }



   /* private void createNewLU(RunnableArgs<MtbColt> onComplete ,RunnableArgs<Exception> onFailed) {
        ColliMagazzinoRESTConsumer.createColloLavorazione(+1, onComplete, onFailed);
    }
*/

    private void saveLU(MtbColt mtbColt) {
        mtbColt.setOperation(CommonModelConsts.OPERATION.INSERT_OR_UPDATE);

        for(int i = 0; i < mtbColt.getMtbColr().size(); i++) {
            mtbColt.getMtbColr().get(i).setOperation(CommonModelConsts.OPERATION.INSERT_OR_UPDATE);
        }


        ColliMagazzinoRESTConsumer.saveCollo(mtbColt, value -> {
            showDataSavedDialog();
        }, ex -> {
            UtilityExceptions.defaultException(mContext, ex);
        });

    }


    private void showDataSavedDialog() {

        DialogSimpleMessageHelper.makeSuccessDialog(
                mContext,
                mContext.getResources().getString(R.string.completed),
                new SpannableString(mContext.getResources().getString(R.string.data_saved)),
                null, () -> {
                    resetMtbColt();
                }).show();

    }
}
