package it.integry.integrywmsnative.gest.picking_libero;


import android.content.Context;
import android.os.Bundle;
import android.text.SpannableString;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;

import androidx.appcompat.widget.AppCompatTextView;
import androidx.core.content.ContextCompat;
import androidx.databinding.DataBindingUtil;
import androidx.databinding.ObservableList;
import androidx.fragment.app.Fragment;
import androidx.recyclerview.widget.LinearLayoutManager;

import com.tfb.fbtoast.FBToast;

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

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.OnListGeneralChangedCallback;
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.IScrollableFragment;
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.VtbDest;
import it.integry.integrywmsnative.core.model.secondary.GestioneEnum;
import it.integry.integrywmsnative.core.settings.SettingsManager;
import it.integry.integrywmsnative.core.utility.UtilityExceptions;
import it.integry.integrywmsnative.core.utility.UtilityToast;
import it.integry.integrywmsnative.databinding.FragmentPickingLiberoBinding;
import it.integry.integrywmsnative.gest.picking_libero.ui.PickingLiberoListAdapter;
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.ElevatedToolbar;
import it.integry.integrywmsnative.ui.SimpleDividerItemDecoration;
import it.integry.integrywmsnative.view.bottom_sheet__mtb_colr_edit.BottomSheetMtbColrEditModalView;
import it.integry.integrywmsnative.view.dialogs.ask_cliente.DialogAskClienteView;
import it.integry.integrywmsnative.view.dialogs.base.DialogSimpleMessageView;
import it.integry.integrywmsnative.view.dialogs.choose_arts_from_mtbcolr_list.DialogChooseArtsFromMtbColrList;
import it.integry.integrywmsnative.view.dialogs.input_quantity_v2.DialogInputQuantityV2DTO;
import it.integry.integrywmsnative.view.dialogs.input_quantity_v2.DialogInputQuantityV2View;

/**
 * A simple {@link Fragment} subclass.
 */
public class PickingLiberoFragment extends BaseFragment implements ITitledFragment, IScrollableFragment, ILifecycleFragment, PickingLiberoViewModel.Listener, BottomSheetMtbColrEditModalView.Listener {

    private FragmentPickingLiberoBinding mBindings;

    @Inject
    PickingLiberoViewModel mViewModel;

    @Inject
    DialogInputQuantityV2View mDialogInputQuantityV2View;

    public BindableBoolean thereIsAnOpenedUL = new BindableBoolean(false);
    public BindableBoolean thereIsntAnOpenedUL = new BindableBoolean(true);
    public BindableBoolean thereIsAnyRowInUL = new BindableBoolean(false);
    public BindableBoolean thereIsAnOpenULWithoutRows = new BindableBoolean(false);

    private final List<Runnable> mOnPreDestroyList = new ArrayList<>();
    private ElevatedToolbar mToolbar;
    private AppCompatTextView mToolbarTitleText;

    private PickingLiberoListAdapter mAdapter;

    private int barcodeScannerIstanceID = -1;

    private GestioneEnum mCurrentGestione;

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

    public static PickingLiberoFragment newInstance(GestioneEnum gestioneEnum) {
        PickingLiberoFragment fragment = new PickingLiberoFragment();
        Bundle args = new Bundle();

        args.putString("gestione", gestioneEnum.getText());

        fragment.setArguments(args);
        return fragment;
    }

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

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        mCurrentGestione = GestioneEnum.fromString(getArguments().getString("gestione"));
    }


    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
                             Bundle savedInstanceState) {
        // Inflate the layout for this fragment
        mBindings = DataBindingUtil.inflate(inflater, R.layout.fragment_picking_libero, container, false);

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

        mViewModel.setListener(this);

        mBindings.setLifecycleOwner(this);
        mBindings.setView(this);

        mToolbar.setRecyclerView(mBindings.pickingLiberoMainList);

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

        this.initRecyclerView();

        boolean flagAskCliente = SettingsManager.iDB().isFlagAskClienteInPickingLibero();
        mViewModel.init(flagAskCliente, mCurrentGestione);

        return mBindings.getRoot();
    }

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

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

        BarcodeManager.enable();
    }


    private void initRecyclerView() {
        mBindings.pickingLiberoMainList.setNestedScrollingEnabled(false);
        mBindings.pickingLiberoMainList.setHasFixedSize(true);
        mBindings.pickingLiberoMainList.setLayoutManager(new LinearLayoutManager(requireActivity()));

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

    private void initAdapter() {
        mAdapter = new PickingLiberoListAdapter(mViewModel.getCurrentMtbColt().getMtbColr());
        mBindings.pickingLiberoMainList.setAdapter(mAdapter);

        this.mAdapter.setOnItemClickListener(clickedMtbColr -> {
            new BottomSheetMtbColrEditModalView(clickedMtbColr)
                    .setListener(this)
                    .show(getParentFragmentManager(), "BottomSheetMtbColrEditModal");
        });
    }

    private void destroyAdapter() {
        mBindings.pickingLiberoMainList.setAdapter(null);
        mAdapter = null;
    }

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

        this.mViewModel.processBarcodeDTO(data, () -> {
            BarcodeManager.enable();
            this.onLoadingEnded();
        });
    };

    public void createNewLU() {
        this.mViewModel.createNewLU(null, null, () -> {
        });
    }

    public void closeLU() {
        destroyAdapter();
        this.mViewModel.closeLU(null);
    }

    @Override
    public void onDestroy() {
        for (Runnable onPreDestroy : mOnPreDestroyList) {
            onPreDestroy.run();
        }
        super.onDestroy();
    }

    @Override
    public void setScrollToolbar(ElevatedToolbar toolbar) {
        mToolbar = toolbar;
    }


    @Override
    public void onLUOpened(MtbColt mtbColt) {
        requireActivity().runOnUiThread(() -> {
            mToolbarTitleText.setText(String.format(getActivity().getText(R.string.lu_number_text).toString(), mtbColt.getNumCollo()));

            initAdapter();

            thereIsAnOpenedUL.set(true);
            thereIsAnyRowInUL.set(mtbColt.getMtbColr().size() > 0, true);

            mtbColt.getMtbColr().addOnListChangedCallback(new OnListGeneralChangedCallback() {
                @Override
                public void onChanged(ObservableList sender) {
                    thereIsAnyRowInUL.set(mtbColt.getMtbColr().size() > 0, true);
                }
            });

            FBToast.successToast(getActivity(), getResources().getString(R.string.data_saved), FBToast.LENGTH_SHORT);
        });
    }

    @Override
    public void onLUClosed() {
        requireActivity().runOnUiThread(() -> {
            mToolbarTitleText.setText(getActivity().getText(R.string.free_picking_title_fragment).toString());
            destroyAdapter();

            thereIsAnyRowInUL.set(false);
            thereIsAnOpenedUL.set(false);
        });
    }

    @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) {
        requireActivity().runOnUiThread(() -> {
            this.onLoadingEnded();

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

            BarcodeManager.enable();
        });
    }

    @Override
    public void onLUClienteRequired(RunnableArgss<VtbDest, String> onComplete, Runnable onAbort) {
        DialogAskClienteView.newInstance(onComplete, onAbort)
                .show(requireActivity().getSupportFragmentManager(), "tag");
    }

    @Override
    public void onArtSelectionRequest(List<MtbColr> mtbColrsToPick, MtbAart mtbAart, RunnableArgs<List<MtbColr>> onComplete, Runnable onAbort) {
        DialogChooseArtsFromMtbColrList
                .newInstance(mtbColrsToPick, mtbAart, onComplete, () -> {
                    onAbort.run();
                    BarcodeManager.enable();
                })
                .show(requireActivity().getSupportFragmentManager(), "tag");
    }

    @Override
    public void onItemDispatched(
            PickingObjectDTO pickingObjectDTO,
            MtbAart mtbAart,
            BigDecimal initialNumCnf,
            BigDecimal initialQtaCnf,
            BigDecimal initialQtaTot,
            BigDecimal totalQtaAvailable,
            BigDecimal totalNumCnfAvailable,
            BigDecimal qtaCnfAvailable,
            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)
                .setTotalQtaAvailable(totalQtaAvailable)
                .setTotalNumCnfAvailable(totalNumCnfAvailable)
                .setQtaCnfAvailable(qtaCnfAvailable)
                .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");
    }

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


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

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

    @Override
    public void onPreDestroy(Runnable onComplete) {
        BarcodeManager.removeCallback(barcodeScannerIstanceID);
        if (thereIsAnOpenedUL.get()) mViewModel.closeLU(onComplete);
        else onComplete.run();
    }

    @Override
    public void addOnPreDestroy(Runnable onPreDestroy) {
        this.mOnPreDestroyList.add(onPreDestroy);
    }
}
