package it.integry.integrywmsnative.gest.rettifica_giacenze;

import android.content.Context;
import android.content.pm.ActivityInfo;
import android.content.res.ColorStateList;
import android.content.res.Resources;
import android.os.Bundle;
import android.text.SpannableString;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.view.inputmethod.EditorInfo;

import androidx.annotation.NonNull;
import androidx.appcompat.widget.AppCompatTextView;
import androidx.core.content.ContextCompat;
import androidx.core.content.res.ResourcesCompat;
import androidx.databinding.DataBindingUtil;
import androidx.databinding.ObservableField;
import androidx.recyclerview.widget.LinearLayoutManager;

import com.google.android.material.textfield.TextInputLayout;
import com.tfb.fbtoast.FBToast;

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

import javax.inject.Inject;

import it.integry.barcode_base_android_library.model.BarcodeScanDTO;
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.di.BindableBoolean;
import it.integry.integrywmsnative.core.expansion.BaseFragment;
import it.integry.integrywmsnative.core.expansion.RunnableArgs;
import it.integry.integrywmsnative.core.expansion.RunnableArgss;
import it.integry.integrywmsnative.core.interfaces.ILifecycleFragment;
import it.integry.integrywmsnative.core.interfaces.ITitledFragment;
import it.integry.integrywmsnative.core.model.MtbAart;
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.settings.SettingsManager;
import it.integry.integrywmsnative.core.utility.UtilityExceptions;
import it.integry.integrywmsnative.core.utility.UtilityString;
import it.integry.integrywmsnative.core.utility.UtilityToast;
import it.integry.integrywmsnative.databinding.FragmentMainRettificaGiacenzeBinding;
import it.integry.integrywmsnative.gest.rettifica_giacenze.dto.FornitoreDTO;
import it.integry.integrywmsnative.gest.rettifica_giacenze.ui.AutoCompleteFornitoreAdapter;
import it.integry.integrywmsnative.gest.rettifica_giacenze.ui.RettificaGiacenzeMainListAdapter;
import it.integry.integrywmsnative.gest.spedizione.exceptions.InvalidPesoKGException;
import it.integry.integrywmsnative.gest.spedizione.model.PickedQuantityDTO;
import it.integry.integrywmsnative.gest.spedizione.model.PickingObjectDTO;
import it.integry.integrywmsnative.ui.SimpleDividerItemDecoration;
import it.integry.integrywmsnative.view.bottom_sheet__mtb_colr_edit.BottomSheetMtbColrEditModalView;
import it.integry.integrywmsnative.view.dialogs.DialogConsts;
import it.integry.integrywmsnative.view.dialogs.ask_position_of_lu.DialogAskPositionOfLUView;
import it.integry.integrywmsnative.view.dialogs.base.DialogSimpleMessageView;
import it.integry.integrywmsnative.view.dialogs.choose_art_from_lista_arts.DialogChooseArtFromListaArtsView;
import it.integry.integrywmsnative.view.dialogs.input_quantity_v2.DialogInputQuantityV2DTO;
import it.integry.integrywmsnative.view.dialogs.input_quantity_v2.DialogInputQuantityV2View;
import it.integry.integrywmsnative.view.dialogs.scan_or_create_lu.DialogScanOrCreateLUView;
import it.integry.integrywmsnative.view.dialogs.yes_no.DialogYesNoView;

public class RettificaGiacenzeFragment extends BaseFragment implements ITitledFragment, ILifecycleFragment, RettificaGiacenzeViewModel.Listener, BottomSheetMtbColrEditModalView.Listener {

    private FragmentMainRettificaGiacenzeBinding mBinding = null;

    @Inject
    RettificaGiacenzeViewModel mViewModel;

    @Inject
    DialogInputQuantityV2View mDialogInputQuantityV2View;

    public BindableBoolean thereIsAnOpenedUL = new BindableBoolean(false);
    public BindableBoolean thereIsntAnOpenedUL = new BindableBoolean(false);

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

    private RettificaGiacenzeMainListAdapter mAdapter;

    private int barcodeScannerIstanceID = -1;

    public RettificaGiacenzeFragment() {
        // Required empty public constructor
    }


    public static RettificaGiacenzeFragment newInstance() {
        RettificaGiacenzeFragment fragment = new RettificaGiacenzeFragment();
        return fragment;
    }

    @Override
    public void onCreate(Bundle savedInstanceState) {
        requireActivity().setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
        super.onCreate(savedInstanceState);
    }

    @Override
    public void onDestroy() {
        requireActivity().setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED);
        super.onDestroy();
    }

    @Override
    public void onAttach(@NonNull Context context) {
        super.onAttach(context);

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

        mViewModel.setListener(this);
    }

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

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


        mBinding.setLifecycleOwner(this);
        mBinding.setView(this);
        mBinding.setViewmodel(mViewModel);


        this.initVars();
        this.initBarcodeReader();
        this.initRecyclerView();

        this.init();

        return mBinding.getRoot();
    }

    private void initVars() {
        thereIsAnOpenedUL.addOnPropertyChangedCallback(() -> {
            thereIsntAnOpenedUL.set(!thereIsAnOpenedUL.get());
        });
    }

    private void initBarcodeReader() {
        barcodeScannerIstanceID = BarcodeManager.addCallback(new BarcodeCallbackDTO()
                .setOnScanSuccessful(onScanSuccessful)
                .setOnScanFailed(ex -> UtilityExceptions.defaultException(getActivity(), ex, false)));
    }

    private void initRecyclerView() {
        mBinding.rettificaGiacenzeMainList.setNestedScrollingEnabled(false);
        mBinding.rettificaGiacenzeMainList.setHasFixedSize(true);
        mBinding.rettificaGiacenzeMainList.setLayoutManager(new LinearLayoutManager(getActivity()));

        SimpleDividerItemDecoration itemDecorator = new SimpleDividerItemDecoration(requireActivity(), SimpleDividerItemDecoration.VERTICAL);
        itemDecorator.setDrawable(ContextCompat.getDrawable(requireActivity(), R.drawable.divider));
        mBinding.rettificaGiacenzeMainList.addItemDecoration(itemDecorator);
    }


    private void initAdapter() {
        mAdapter = new RettificaGiacenzeMainListAdapter(mViewModel.getCurrentMtbColt().getMtbColr());
        mAdapter.setEmptyView(mBinding.rettificaGiacenzeEmptyView);


        this.mAdapter.setOnItemClickListener(clickedMtbColr -> {
            new BottomSheetMtbColrEditModalView(clickedMtbColr)
                    .setListener(this)
                    .show(getParentFragmentManager(), "tag");
//            mBinding.bottomSheetMtbColrEdit.setMtbColr(clickedMtbColr);
//            mBinding.bottomSheetMtbColrEdit.expand();
        });

        mBinding.rettificaGiacenzeMainList.setAdapter(mAdapter);
    }

    private void destroyAdapter() {
        mBinding.rettificaGiacenzeMainList.setAdapter(null);
        mAdapter = null;
    }

    private void init() {
        mBinding.autoCompleteFornitori.setOnFocusChangeListener((v, hasFocus) -> {
            setUIToForn();
        });

        mBinding.inputCodArtDescrForn.setOnFocusChangeListener((v, hasFocus) -> {
            setUIToForn();
        });

        mBinding.inputCodArtDescrInt.setOnFocusChangeListener((v, hasFocus) -> {
            setUIToIntArt();
        });

        mViewModel.init(
                SettingsManager.i().getUser().getFullname(),
                SettingsManager.i().getUserSession().getDepo().getCodMdep());
    }

    @Override
    public void onCreateActionBar(AppCompatTextView titleText, Context context) {
        titleText.setText(context.getText(R.string.rettifica_giacenze_fragment_title).toString());
    }


    private final RunnableArgs<BarcodeScanDTO> onScanSuccessful = data -> {
        this.onLoadingStarted();

        this.mViewModel.processBarcodeDTO(data, this::onLoadingEnded);
    };


    public void setUIToForn() {
        mBinding.rettificaGiacenzeFornCheckBox.setChecked(true);
        mBinding.rettificaGiacenzeFornLayout.setBackground(ResourcesCompat.getDrawable(getActivity().getResources(), R.drawable.circular_background_left, null));
        mBinding.rettificaGiacenzeFornLayout.setBackgroundTintList(ColorStateList.valueOf(getActivity().getResources().getColor(R.color.alpha_blue_500)));

        mBinding.rettificaGiacenzeArtIntCheckBox.setChecked(false);
        mBinding.rettificaGiacenzeArtIntLayout.setBackground(null);
        mBinding.rettificaGiacenzeArtIntLayout.setBackgroundTintList(null);
    }


    public void setUIToIntArt() {
        mBinding.rettificaGiacenzeArtIntCheckBox.setChecked(true);
        mBinding.rettificaGiacenzeArtIntLayout.setBackground(ResourcesCompat.getDrawable(getActivity().getResources(), R.drawable.circular_background_left, null));
        mBinding.rettificaGiacenzeArtIntLayout.setBackgroundTintList(ColorStateList.valueOf(getActivity().getResources().getColor(R.color.alpha_blue_500)));

        mBinding.rettificaGiacenzeFornCheckBox.setChecked(false);
        mBinding.rettificaGiacenzeFornLayout.setBackground(null);
        mBinding.rettificaGiacenzeFornLayout.setBackgroundTintList(null);
    }

    @Override
    public void onFornitoriLoaded(ArrayList<FornitoreDTO> fornitoriList) {
        AutoCompleteFornitoreAdapter autoCompleteFornitoreAdapter = new AutoCompleteFornitoreAdapter(getActivity(), fornitoriList);
        mBinding.autoCompleteFornitori.setAdapter(autoCompleteFornitoreAdapter);
        mBinding.autoCompleteFornitori.setDropDownWidth(getActivity().getResources().getDisplayMetrics().widthPixels);

        mBinding.inputCodArtDescrForn.setOnEditorActionListener((v, actionId, event) -> {
            if (actionId == EditorInfo.IME_ACTION_DONE) {
                resetAllError();

                if (UtilityString.isNullOrEmpty(mBinding.autoCompleteFornitori.getText().toString())) {
                    setError(mBinding.autoCompleteFornitoriLayout, getActivity().getResources().getText(R.string.error).toString());
                    return true;
                }

                if (UtilityString.isNullOrEmpty(mBinding.inputCodArtDescrForn.getText().toString())) {
                    setError(mBinding.layoutCodArtDescrForn, getActivity().getResources().getText(R.string.error).toString());
                    return true;
                }

                mViewModel.searchArtFor(
                        mBinding.autoCompleteFornitori.getText().toString(),
                        mBinding.inputCodArtDescrForn.getText().toString());
                return true;
            }
            return false;
        });


        mBinding.inputCodArtDescrInt.setOnEditorActionListener((v, actionId, event) -> {
            if (actionId == EditorInfo.IME_ACTION_DONE) {
                resetAllError();

                if (UtilityString.isNullOrEmpty(mBinding.inputCodArtDescrInt.getText().toString())) {
                    setError(mBinding.layoutCodArtDescrInt, getActivity().getResources().getText(R.string.error).toString());
                    return true;
                }

                mViewModel.searchArtInt(mBinding.inputCodArtDescrInt.getText().toString(), null);
                return true;
            }
            return false;
        });
    }

    @Override
    public void onArtListLoaded(ArrayList<MtbAart> artList, RunnableArgs<MtbAart> onArtChoosed) {
        new DialogChooseArtFromListaArtsView(artList, onArtChoosed)
                .show(requireActivity().getSupportFragmentManager(), "tag");
    }

    @Override
    public void onLUOpenRequest(RunnableArgss<MtbColt, Boolean> onComplete) {
        DialogScanOrCreateLUView.newInstance(true, false, (mtbColt, created) -> {
            if (mtbColt == null) {
                popMe();
            } else {
                onComplete.run(mtbColt, created);
            }
        }).show(requireActivity().getSupportFragmentManager(), "tag");
    }

    @Override
    public void onLUOpened(MtbColt mtbColt) {
        initAdapter();

        this.currentMtbColtObs.set(mtbColt);
        thereIsAnOpenedUL.set(true);
    }

    @Override
    public void onLUClosed() {
        destroyAdapter();

        this.currentMtbColtObs.set(null);
        thereIsAnOpenedUL.set(false);

        this.mViewModel.requestLU();
        /*if (getActivity() != null) ((IPoppableActivity) getActivity()).pop();*/
    }

    @Override
    public void onMtbColrDeleteRequest(RunnableArgs<Boolean> onComplete) {
        String text = getResources().getString(R.string.alert_delete_mtb_colr);
        DialogSimpleMessageView.makeWarningDialog(new SpannableString(text),
                        null,
                        () -> onComplete.run(true),
                        () -> onComplete.run(false)
                )
                .show(requireActivity().getSupportFragmentManager(), "tag");
    }

    @Override
    public void onError(Exception ex) {
        this.onLoadingEnded();
        BarcodeManager.enable();

        if (ex instanceof InvalidPesoKGException) {
            UtilityToast.showToast(ex.getMessage());
        } else {
            UtilityExceptions.defaultException(requireActivity(), ex);
        }
    }

    @Override
    public void onItemDispatched(
            PickingObjectDTO pickingObjectDTO,
            MtbAart mtbAart,
            BigDecimal initialNumCnf,
            BigDecimal initialQtaCnf,
            BigDecimal initialQtaTot,
            BigDecimal totalQtaInWarehouse,
            BigDecimal totalNumCnfInWarehouse,
            BigDecimal totalQtaCommitted,
            BigDecimal totalNumCnfCommitted,
            BigDecimal totalQtaToBeTaken,
            BigDecimal totalNumCnfToBeTaken,
            BigDecimal qtaCnfToBeTaken,
            String partitaMag,
            Date dataScad,
            boolean canOverflowOrderQuantity,
            boolean canPartitaMagBeChanged,
            boolean canLUBeClosed,
            RunnableArgss<PickedQuantityDTO, Boolean> onComplete) {

        DialogInputQuantityV2DTO dialogInputQuantityV2DTO = new DialogInputQuantityV2DTO()
                .setMtbAart(mtbAart)
                .setInitialNumCnf(initialNumCnf)
                .setInitialQtaCnf(initialQtaCnf)
                .setInitialQtaTot(initialQtaTot)
                .setTotalQtaInWarehouse(totalQtaInWarehouse)
                .setTotalNumCnfInWarehouse(totalNumCnfInWarehouse)
                .setTotalQtaCommitted(totalQtaCommitted)
                .setTotalNumCnfCommitted(totalNumCnfCommitted)
                .setTotalQtaToBeTaken(totalQtaToBeTaken)
                .setTotalNumCnfToBeTaken(totalNumCnfToBeTaken)
                .setQtaCnfToBeTaken(qtaCnfToBeTaken)
                .setPartitaMag(partitaMag)
                .setDataScad(dataScad)
                .setCanOverflowOrderQuantity(canOverflowOrderQuantity)
                .setCanPartitaMagBeChanged(canPartitaMagBeChanged)
                .setCanLUBeClosed(canLUBeClosed);

        if (!mDialogInputQuantityV2View.isVisible())
            mDialogInputQuantityV2View
                    .setDialogInputQuantityV2DTO(dialogInputQuantityV2DTO)
                    .setOnComplete((resultDTO, shouldCloseLU) -> {
                        PickedQuantityDTO pickedQuantityDTO = new PickedQuantityDTO()
                                .setNumCnf(resultDTO.getNumCnf())
                                .setQtaCnf(resultDTO.getQtaCnf())
                                .setQtaTot(resultDTO.getQtaTot())
                                .setPartitaMag(resultDTO.getPartitaMag())
                                .setDataScad(resultDTO.getDataScad());

                        this.onLoadingStarted();
                        onComplete.run(pickedQuantityDTO, shouldCloseLU);
                    })
                    .setOnAbort(this::onLoadingEnded)
                    .show(requireActivity().getSupportFragmentManager(), "tag");

        else this.onLoadingEnded();
    }

    @Override
    public void onRowSaved() {
        FBToast.successToast(requireActivity(), getResources().getString(R.string.data_saved), FBToast.LENGTH_SHORT);
    }


    private void setError(TextInputLayout textInputLayout, String message) {
        textInputLayout.setErrorEnabled(true);
        textInputLayout.setError(message);
        textInputLayout.setErrorIconDrawable(null);
    }

    private void resetAllError() {
        resetError(mBinding.autoCompleteFornitoriLayout);
        resetError(mBinding.layoutCodArtDescrForn);
        resetError(mBinding.layoutCodArtDescrInt);
    }

    private void resetTexts() {
        mBinding.inputCodArtDescrForn.setText("");
        mBinding.inputCodArtDescrInt.setText("");
    }

    private void resetError(TextInputLayout textInputLayout) {
        textInputLayout.setErrorEnabled(false);
        textInputLayout.setError(null);
    }

    @Override
    public void onMtbColrEdit(MtbColr mtbColr) {
        this.mViewModel.dispatchRowEdit(mtbColr);
    }

    @Override
    public void onMtbColrDelete(MtbColr mtbColr) {
        this.mViewModel.deleteRow(mtbColr);
    }

    @Override
    public void onLUSuccessullyPrinted() {
        Resources res = getResources();
        String errorMessage = res.getText(R.string.alert_print_completed_message).toString();
        DialogSimpleMessageView
                .makeSuccessDialog(res.getText(R.string.completed).toString(), new SpannableString(errorMessage), null, null)
                .show(getActivity().getSupportFragmentManager(), "tag");
    }

    @Override
    public void onLUPrintRequest(RunnableArgs<Boolean> onComplete) {
        DialogSimpleMessageView.makeInfoDialog(
                        getActivity().getResources().getString(R.string.action_print_ul),
                        new SpannableString(getActivity().getResources().getString(R.string.ask_print_message)),
                        null,
                        () -> onComplete.run(true),
                        () -> onComplete.run(false))
                .show(getActivity().getSupportFragmentManager(), "tag");
    }

    @Override
    public void onLUPrintError(Exception ex, Runnable onComplete) {
        DialogSimpleMessageView.makeErrorDialog(
                        new SpannableString(ex.getMessage()),
                        null,
                        null,
                        R.string.button_ignore_print,
                        onComplete)
                .show(requireActivity().getSupportFragmentManager(), "tag");
    }

    @Override
    public void onLUPositionChangeRequest(RunnableArgss<Boolean, MtbDepoPosizione> onComplete) {
        DialogYesNoView.newInstance(null, "Vuoi cambiare la posizione della UL corrente?", result -> {
            switch (result) {
                case YES:
                    DialogAskPositionOfLUView.makeBase(false, (status, mtbDepoPosizione) -> {
                                if (status == DialogConsts.Results.ABORT) {
                                    onComplete.run(false, null);
                                } else {
                                    if (mtbDepoPosizione != null) {
                                        onComplete.run(true, mtbDepoPosizione);
                                    } else {
                                        onComplete.run(true, null);
                                    }
                                }
                            }, this::onError)
                            .show(requireActivity().getSupportFragmentManager(), "tag");
                    break;

                case NO:
                    onComplete.run(false, null);
                    break;
            }
        }).show(requireActivity().getSupportFragmentManager(), "tag");
    }

    @Override
    public void onPreDestroy(Runnable onComplete) {
        if (mViewModel.getCurrentMtbColt() != null)
            mViewModel.closeLU(false);
        else {
            BarcodeManager.removeCallback(barcodeScannerIstanceID);
            onComplete.run();
        }
    }
}
