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

import android.app.Dialog;
import android.content.DialogInterface;
import android.os.Bundle;
import android.text.Editable;
import android.text.TextWatcher;
import android.view.LayoutInflater;
import android.view.WindowManager;
import android.widget.TextView;
import android.widget.Toast;

import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.appcompat.widget.AppCompatTextView;

import com.google.android.material.dialog.MaterialAlertDialogBuilder;
import com.google.android.material.textfield.TextInputLayout;

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

import it.integry.barcode_base_android_library.model.BarcodeScanDTO;
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.expansion.RunnableArgss;
import it.integry.integrywmsnative.core.model.MtbDepoPosizione;
import it.integry.integrywmsnative.core.utility.UtilityBarcode;
import it.integry.integrywmsnative.core.utility.UtilityPosizione;
import it.integry.integrywmsnative.databinding.DialogAskPositionOfLuBinding;
import it.integry.integrywmsnative.view.dialogs.DialogConsts;

public class DialogAskPositionOfLUView extends BaseDialogFragment implements DialogInterface.OnShowListener {

    private DialogAskPositionOfLuBinding mBindings;
    private DialogAskPositionOfLUAdapter viewpagerAdapter;
    private int mBarcodeScannerIstanceID;

    private boolean mCheckForLineaProd;

    private MtbDepoPosizione currentMtbDepoPosizione;

    private RunnableArgss<DialogConsts.Results, MtbDepoPosizione> onComplete;
    private RunnableArgs<Exception> onFailed;

    private TextInputLayout livelloTextInputLayout;

    private boolean completedFlow = false;

    public static DialogAskPositionOfLUView makeBase(boolean checkForLineaProd, RunnableArgss<DialogConsts.Results, MtbDepoPosizione> onComplete, RunnableArgs<Exception> onFailed) {
        return new DialogAskPositionOfLUView(checkForLineaProd, onComplete, onFailed);
    }

    private DialogAskPositionOfLUView(boolean checkForLineaProd, RunnableArgss<DialogConsts.Results, MtbDepoPosizione> onComplete, RunnableArgs<Exception> onFailed) {
        super();

        this.mCheckForLineaProd = checkForLineaProd;
        this.onComplete = onComplete;
        this.onFailed = onFailed;
    }

    @NonNull
    @Override
    public Dialog onCreateDialog(@Nullable Bundle savedInstanceState) {
        this.initBarcode();

        mBindings = DialogAskPositionOfLuBinding.inflate(LayoutInflater.from(requireActivity()), null, false);
        mBindings.setLifecycleOwner(this);

        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);

        viewpagerAdapter = new DialogAskPositionOfLUAdapter(requireContext(), views);
        mBindings.viewpager.setAdapter(viewpagerAdapter);
        mBindings.viewpager.beginFakeDrag();

        var alertDialog = new MaterialAlertDialogBuilder(requireContext())
                .setView(mBindings.getRoot())
                .setCancelable(false)
                .create();
        alertDialog.setCanceledOnTouchOutside(false);
        alertDialog.setOnShowListener(this);
        return alertDialog;
    }

    @Override
    public void onStart() {
        super.onStart();

        if (getDialog() != null) {
            getDialog().getWindow().clearFlags(WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE);
            getDialog().getWindow().clearFlags(WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM);
        }
    }

    @Override
    public void onShow(DialogInterface dialog) {
        ((AppCompatTextView) viewpagerAdapter.getPage(0)
                .findViewById(R.id.description_text))
                .setText(mCheckForLineaProd ? R.string.ask_production_line_of_lu_message : R.string.ask_position_of_lu_message);

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

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

        livelloTextInputLayout = viewpagerAdapter.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) {

            }
        });
    }

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

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

    private void initBarcode() {
        mBarcodeScannerIstanceID = BarcodeManager.addCallback(new BarcodeCallbackDTO()
                .setOnScanSuccessful(onScanSuccessfull)
                .setOnScanFailed(this::onError));

        BarcodeManager.enable();
    }

    @Override
    public void onDismiss(@NonNull DialogInterface dialog) {
        BarcodeManager.removeCallback(mBarcodeScannerIstanceID);
        if (!completedFlow) onComplete.run(DialogConsts.Results.ABORT, null);
        super.onDismiss(dialog);
    }


    private final RunnableArgs<BarcodeScanDTO> onScanSuccessfull = data -> {
        BarcodeManager.disable();

        if (!isOnLivelloPage()) {

            if (UtilityBarcode.isEtichettaPosizione(data)) {

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

                if (!mCheckForLineaProd && !currentMtbDepoPosizione.isFlagLineaProduzione() && UtilityPosizione.isPosizioneWithLivello(foundPosizione)) {
                    askLivello();
                    BarcodeManager.enable();
                } else {
                    completedFlow = true;
                    if (onComplete != null)
                        onComplete.run(DialogConsts.Results.YES, foundPosizione);

                    dismiss();
                    BarcodeManager.enable();
                }

            } else {
                BarcodeManager.enable();
                Toast.makeText(requireContext(), "Barcode non riconosciuto", Toast.LENGTH_SHORT)
                        .show();
            }
        } else {
            Toast.makeText(requireContext(), "Barcode non riconosciuto", Toast.LENGTH_SHORT)
                    .show();
            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();

            completedFlow = true;
            if (onComplete != null) onComplete.run(DialogConsts.Results.YES, foundPosizione);
            dismiss();

        } else {
            setLevelError(requireContext().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(requireContext().getResources().getString(R.string.not_valid));
    }

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

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


    private void onLevelAbort() {
        completedFlow = true;
        onComplete.run(DialogConsts.Results.ABORT, null);
        dismiss();
    }
}
