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

import android.app.Dialog;
import android.app.ProgressDialog;
import android.content.Context;

import androidx.databinding.DataBindingUtil;
import com.google.android.material.textfield.TextInputLayout;
import android.text.Editable;
import android.text.TextWatcher;
import android.view.LayoutInflater;
import android.widget.TextView;

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

import it.integry.integrywmsnative.R;
import it.integry.integrywmsnative.core.REST.consumers.ColliMagazzinoRESTConsumer;
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.model.MtbColt;
import it.integry.integrywmsnative.core.model.MtbDepoPosizione;
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.databinding.DialogAskPositionOfLuBinding;
import it.integry.plugins.barcode_base_library.model.BarcodeScanDTO;

public class DialogAskPositionOfLU {


    private Context mContext;
    private DialogAskPositionOfLuBinding mBinding;
    private MtbColt mtbColt;

    private MtbDepoPosizione currentMtbDepoPosizione;

    private Dialog mDialog;

    private RunnableArgs<MtbDepoPosizione> onComplete;
    private RunnableArgs<Exception> onFailed;

    private TextInputLayout livelloTextInputLayout;

    private boolean completedFlow = false;

    public static Dialog makeBase(final Context context, MtbColt mtbColtToUpdate, RunnableArgs<MtbDepoPosizione> onComplete, RunnableArgs<Exception> onFailed) {
        return new DialogAskPositionOfLU(context, mtbColtToUpdate, onComplete, onFailed).mDialog;
    }

    public DialogAskPositionOfLU(Context context, MtbColt mtbColtToUpdate, RunnableArgs<MtbDepoPosizione> onComplete, RunnableArgs<Exception> onFailed) {
        mContext = context;
        mtbColt = mtbColtToUpdate;

        this.onComplete = onComplete;
        this.onFailed = onFailed;

        LayoutInflater inflater = (LayoutInflater) context.getSystemService( Context.LAYOUT_INFLATER_SERVICE );
        mBinding = DataBindingUtil.inflate(inflater, R.layout.dialog_ask_position_of_lu, null, false);
        mBinding.setMContext(mContext);

        List<Integer> views = new ArrayList<>();
        views.add(R.layout.dialog_ask_position_of_lu__page1);
        views.add(R.layout.dialog_ask_position_of_lu__page2);

        DialogAskPositionOfLUAdapter adapter = new DialogAskPositionOfLUAdapter(mContext, views);
        mBinding.viewpager.setAdapter(adapter);
        mBinding.viewpager.beginFakeDrag();


        mDialog = new Dialog(mContext);
        mDialog.setContentView(mBinding.getRoot());
        mDialog.setCanceledOnTouchOutside(false);

        mDialog.setOnShowListener(dialog -> {
            adapter.getPage(1).findViewById(R.id.button_confirm).setOnClickListener(v -> {
                String levelNumber = ((TextView)adapter.getPage(1).findViewById(R.id.level_number)).getText().toString();
                onLevelConfirm(levelNumber);
            });

            adapter.getPage(1).findViewById(R.id.button_abort).setOnClickListener(v -> {
                onLevelAbort();
            });

            livelloTextInputLayout = adapter.getPage(1).findViewById(R.id.level_number_layout);

            livelloTextInputLayout.getEditText().addTextChangedListener(new TextWatcher() {
                @Override
                public void beforeTextChanged(CharSequence s, int start, int count, int after) {

                }

                @Override
                public void onTextChanged(CharSequence s, int start, int before, int count) {
                    if(livelloTextInputLayout.getEditText().getText() != null) {
                        validateLevel(livelloTextInputLayout.getEditText().getText().toString());
                    } else resetLevelError();
                }

                @Override
                public void afterTextChanged(Editable s) {

                }
            });
        });

        setupBarcode();
    }


    private void askLivello() {
        mBinding.viewpager.setCurrentItem(1, true);
    }

    private boolean isOnLivelloPage() {
        return mBinding.viewpager.getCurrentItem() == 1;
    }

    private void setupBarcode() {

        int barcodeIstanceID = BarcodeManager.addCallback(new BarcodeCallbackDTO()
                .setOnScanSuccessfull(onScanSuccessfull)
                .setOnScanFailed(ex -> UtilityExceptions.defaultException(mContext, ex, false)));

        mDialog.setOnDismissListener(dialog -> {
            BarcodeManager.removeCallback(barcodeIstanceID);
            if(!completedFlow) onComplete.run(null);
        });

    }


    private RunnableArgs<BarcodeScanDTO> onScanSuccessfull = data -> {

        BarcodeManager.disable();

        if(!isOnLivelloPage()) {

            if (UtilityBarcode.isEtichettaPosizione(data)) {

                MtbDepoPosizione foundPosizione = UtilityPosizione.getFromCache(data.getStringValue());

                currentMtbDepoPosizione = foundPosizione;

                if (UtilityPosizione.isPosizioneWithLivello(foundPosizione)) {
                    askLivello();
                    BarcodeManager.enable();
                } else {
                    updatePosizione(foundPosizione, () -> {
                        completedFlow = true;
                        BarcodeManager.enable();
                        if(onComplete != null) onComplete.run(foundPosizione);
                    }, ex -> {
                        completedFlow = true;
                        BarcodeManager.enable();
                        onFailed.run(ex);
                    });
                }

            } else {
                BarcodeManager.enable();
            }
        } else {
            BarcodeManager.enable();
        }
    };


    private void onLevelConfirm(String levelString) {

        String newPosizione = currentMtbDepoPosizione.getPosizione().substring(0, currentMtbDepoPosizione.getPosizione().length()-1);
        newPosizione += levelString;

        MtbDepoPosizione foundPosizione = UtilityPosizione.getFromCache(newPosizione);

        if(foundPosizione != null) {
            resetLevelError();
            ProgressDialog progressDialog = UtilityProgress.createDefaultProgressDialog(mContext);

            ColliMagazzinoRESTConsumer.changePosizione(mtbColt, foundPosizione, () -> {
                progressDialog.dismiss();
                completedFlow = true;
                onComplete.run(foundPosizione);
                mDialog.dismiss();
            }, ex -> {
                UtilityExceptions.defaultException(mContext, ex, progressDialog);
                completedFlow = true;
                onFailed.run(ex);
                mDialog.dismiss();
            });

        } else {
            setLevelError(mContext.getResources().getString(R.string.not_valid));
        }
    }

    private void validateLevel(String levelString) {
        String newPosizione = currentMtbDepoPosizione.getPosizione().substring(0, currentMtbDepoPosizione.getPosizione().length()-1);
        newPosizione += levelString;

        if(UtilityPosizione.getFromCache(newPosizione) != null) {
            resetLevelError();
        } else setLevelError(mContext.getResources().getString(R.string.not_valid));
    }

    private void setLevelError(String message){
        livelloTextInputLayout.setErrorEnabled(true);
        livelloTextInputLayout.setError(message);
    }

    private void resetLevelError() {
        livelloTextInputLayout.setError(null);
    }


    private void onLevelAbort() {
        completedFlow = true;
        onComplete.run(null);
        mDialog.dismiss();
    }

    private void updatePosizione(MtbDepoPosizione mtbDepoPosizione, Runnable onComplete, RunnableArgs<Exception> onFailed) {

        final ProgressDialog progressDialog = UtilityProgress.createDefaultProgressDialog(mContext);

        ColliMagazzinoRESTConsumer.changePosizione(mtbColt, mtbDepoPosizione, () -> {
            progressDialog.dismiss();
            onComplete.run();
        }, ex -> {
            progressDialog.dismiss();
            onFailed.run(ex);
        });

    }




}
