package it.integry.integrywmsnative.gest.picking_resi;

import android.content.Context;
import android.content.Intent;
import android.content.res.Resources;
import android.os.Bundle;
import android.text.SpannableString;

import androidx.databinding.DataBindingUtil;
import androidx.databinding.ObservableArrayList;
import androidx.recyclerview.widget.LinearLayoutManager;

import com.annimon.stream.Stream;
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.data_cache.DataCache;
import it.integry.integrywmsnative.core.di.BindableBoolean;
import it.integry.integrywmsnative.core.expansion.BaseActivity;
import it.integry.integrywmsnative.core.expansion.RunnableArgs;
import it.integry.integrywmsnative.core.expansion.RunnableArgss;
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.rest.model.DocumentoResoDTO;
import it.integry.integrywmsnative.core.settings.SettingsManager;
import it.integry.integrywmsnative.core.utility.UtilityBigDecimal;
import it.integry.integrywmsnative.core.utility.UtilityDate;
import it.integry.integrywmsnative.core.utility.UtilityExceptions;
import it.integry.integrywmsnative.core.utility.UtilityResources;
import it.integry.integrywmsnative.core.utility.UtilityString;
import it.integry.integrywmsnative.core.utility.UtilityToast;
import it.integry.integrywmsnative.databinding.ActivityPickingResiBinding;
import it.integry.integrywmsnative.gest.picking_resi.ui.PickingResiListAdapter;
import it.integry.integrywmsnative.gest.picking_resi.ui.PickingResiListModel;
import it.integry.integrywmsnative.gest.picking_resi.rest.WithdrawableDtbDocr;
import it.integry.integrywmsnative.gest.spedizione.exceptions.InvalidPesoKGException;
import it.integry.integrywmsnative.gest.spedizione.model.PickedQuantityDTO;
import it.integry.integrywmsnative.view.bottom_sheet__lu_content.BottomSheetFragmentLUContentView;
import it.integry.integrywmsnative.view.bottom_sheet__lu_content.BottomSheetFragmentLUContentViewModel;
import it.integry.integrywmsnative.view.dialogs.ask_should_print.DialogAskShouldPrint;
import it.integry.integrywmsnative.view.dialogs.base.DialogSimpleMessageView;
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.note_aggiuntive_lu.NoteAggiuntiveLUDialog;

public class PickingResiActivity extends BaseActivity implements BottomSheetFragmentLUContentView.Listener, BottomSheetFragmentLUContentViewModel.Listener, PickingResiViewModel.Listener {


    private ActivityPickingResiBinding mBindings;

    @Inject
    PickingResiViewModel mViewmodel;

    private BottomSheetFragmentLUContentViewModel mBottomSheetFragmentLUContentViewModel;

    private ObservableArrayList<PickingResiListModel> mPickingResiMutableData = new ObservableArrayList<>();

    public BindableBoolean noLUPresent = new BindableBoolean(true);
    public BindableBoolean noItemsToPick = new BindableBoolean(false);
    public BindableBoolean bottomSheetEnabled = new BindableBoolean(false);

    private String mTitle;
    private List<DocumentoResoDTO> mDocumentiResiList;

    private int barcodeScannerIstanceID = -1;

    private boolean mShouldCloseActivity;

    public static void startActivity(Context context, String activityTitle, List<DocumentoResoDTO> documentoResoDTOList, Integer segno) {
        Intent intent = new Intent(context, PickingResiActivity.class);

        intent.putExtra("activity_title", activityTitle);

        String consegneCacheKey = DataCache.addItem(documentoResoDTOList);
        intent.putExtra("key", consegneCacheKey);

        intent.putExtra("segno", segno);

        context.startActivity(intent);
    }


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

        mTitle = getIntent().getStringExtra("activity_title");
        mDocumentiResiList = DataCache.retrieveItem(getIntent().getStringExtra("key"));
        int defaultSegnoLU = getIntent().getIntExtra("segno", +1);

        mBindings = DataBindingUtil.setContentView(this, R.layout.activity_picking_resi);

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

        mViewmodel.setListener(this);

        setSupportActionBar(mBindings.toolbar);
        getSupportActionBar().setDisplayHomeAsUpEnabled(true);

        getSupportActionBar().setTitle(mTitle);

        mBindings.setLifecycleOwner(this);
        mBindings.setPickingResiView(this);

        mBindings.bottomSheetLuContent.init(mBindings.bottomSheetLuContent, null);
        mBottomSheetFragmentLUContentViewModel = mBindings.bottomSheetLuContent.getViewModelInstance();
        mBindings.bottomSheetLuContent.setListener(this);
        mBottomSheetFragmentLUContentViewModel.setListener(this);


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


        String codMdep = SettingsManager.i().getUserSession().getDepo().getCodMdep();

        this.mViewmodel.init(mDocumentiResiList, defaultSegnoLU, codMdep);
    }

    @Override
    public boolean onSupportNavigateUp() {
        onBackPressed();
        return true;
    }

    @Override
    public void onBackPressed() {

        if (this.mBindings.bottomSheetLuContent.isExpanded()) {
            this.mBindings.bottomSheetLuContent.collapse();
        } else if (!noLUPresent.get()) {
            this.mShouldCloseActivity = true;
            BarcodeManager.removeCallback(barcodeScannerIstanceID);
            this.mViewmodel.closeLU(true);
        } else {
            BarcodeManager.removeCallback(barcodeScannerIstanceID);
            super.onBackPressed();
        }
    }


    private void initVars() {
        this.noLUPresent.addOnPropertyChangedCallback(() -> {
            this.bottomSheetEnabled.set(!this.noLUPresent.get());
        });
    }

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

    private void initRecyclerView() {
        this.mBindings.elevatedToolbar.setRecyclerView(this.mBindings.mainList);

        this.mViewmodel.getPickingList().observe(this, updatedData -> {
            this.mPickingResiMutableData.clear();
            this.mPickingResiMutableData.addAll(convertDataModelToListModel(updatedData));
            this.noItemsToPick.set(updatedData.isEmpty());
        });

        PickingResiListAdapter pickingResiListAdapter = new PickingResiListAdapter(this, mPickingResiMutableData);
        this.mBindings.mainList.setAdapter(pickingResiListAdapter);
        this.mBindings.mainList.setLayoutManager(new LinearLayoutManager(this));

        pickingResiListAdapter.setOnItemClicked((clickedItem, refMtbColt) -> {
            if (!noLUPresent.get()) {
                this.mViewmodel.dispatchOrdineRow(clickedItem, refMtbColt);
            }
        });
    }


    private List<PickingResiListModel> convertDataModelToListModel(List<WithdrawableDtbDocr> dataList) {
        List<PickingResiListModel> pickingResiListModels = new ArrayList<>();

        List<WithdrawableDtbDocr> tmpList = Stream.of(dataList)
                .filter(x -> !x.isHidden() && UtilityBigDecimal.greaterThan(x.getQtaDoc(), BigDecimal.ZERO))
                .toList();

        Stream.of(tmpList)
                .sortBy(x -> x.getNumDoc() + " " + x.getDataDocS() + " " + x.getCodDtip() + " " + x.getSerDoc() + " " + x.getCodAnag() + " " + x.getIdRiga())
                .forEach(x -> {

                    PickingResiListModel pickingResiListModel = new PickingResiListModel();

                    pickingResiListModel.setGroupTitle(x.getCodDtip() + " - N° " + x.getNumDoc() + " del " + UtilityDate.formatDate(x.getDataDocD(), UtilityDate.COMMONS_DATE_FORMATS.DM_HUMAN));
                    pickingResiListModel.setBadge1(x.getCodMart());
                    pickingResiListModel.setDescrizione(UtilityString.isNull(x.getDescrizioneEstesa(), x.getDescrizione()));
                    pickingResiListModel.setActive(true);
                    pickingResiListModel.setOriginalModel(x);

                    BigDecimal qtaColEvasa = BigDecimal.ZERO;
                    BigDecimal numCnfColEvasa = BigDecimal.ZERO;

                    for (MtbColr mtbColr : x.getWithdrawRows()) {
                        qtaColEvasa = qtaColEvasa.add(mtbColr.getQtaCol());
                        numCnfColEvasa = numCnfColEvasa.add(mtbColr.getNumCnf());
                    }

                    if (SettingsManager.iDB().isFlagForceAllToColli() || (x.getMtbAart() == null || !x.getMtbAart().isFlagQtaCnfFissaBoolean())) {
                        pickingResiListModel.setUntMis(UtilityResources.getString(R.string.unt_mis_col));
                        pickingResiListModel.setQtaEvasa(numCnfColEvasa);
                        pickingResiListModel.setQtaTot(x.getNumCnf());

                    } else {
                        if (x.getMtbAart() != null)
                            pickingResiListModel.setUntMis(x.getMtbAart().getUntMis());
                        else pickingResiListModel.setUntMis(x.getUntDoc());
                        pickingResiListModel.setQtaEvasa(qtaColEvasa);
                        pickingResiListModel.setQtaTot(x.getQtaDoc());
                    }


                    pickingResiListModels.add(pickingResiListModel);
                });

        return pickingResiListModels;
    }

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

        this.openProgress();

        this.mViewmodel.processBarcodeDTO(data, () -> {
            BarcodeManager.enable();
            this.closeProgress();
        });
    };

    public void createNewLU() {
        this.mBindings.mainFab.close(true);

        this.openProgress();

        this.mViewmodel.createNewLU(null, null, () -> {
            this.closeProgress();
        });
    }

    public void removeListFilter() {
        this.mViewmodel.resetMatchedRows();
    }

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

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

    @Override
    public void onBottomSheetLUClose() {
        this.mViewmodel.closeLU(true);
    }

    @Override
    public void onNoteAggiuntiveRequired(RunnableArgs<String> onComplete, Runnable onAbort) {
        NoteAggiuntiveLUDialog.make(this, onComplete, onAbort).show();
    }

    @Override
    public void onError(Exception ex) {
        this.closeProgress();

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

        BarcodeManager.enable();
    }

    @Override
    public void onItemDispatched(MtbAart mtbAart,
                                 BigDecimal initialNumCnf,
                                 BigDecimal initialQtaCnf,
                                 BigDecimal initialQtaTot,
                                 BigDecimal totalQtaAvailable,
                                 BigDecimal totalNumCnfAvailable,
                                 BigDecimal qtaCnfAvailable,
                                 String partitaMag,
                                 Date dataScad,
                                 RunnableArgss<PickedQuantityDTO, Boolean> onComplete) {
        DialogInputQuantityV2DTO dialogInputQuantityV2DTO = new DialogInputQuantityV2DTO()
                .setMtbAart(mtbAart)
                .setInitialNumCnf(initialNumCnf)
                .setInitialQtaCnf(initialQtaCnf)
                .setInitialQtaTot(initialQtaTot)
                .setTotalQtaAvailable(totalQtaAvailable)
                .setTotalNumCnfAvailable(totalNumCnfAvailable)
                .setQtaCnfAvailable(qtaCnfAvailable)
                .setPartitaMag(partitaMag)
                .setDataScad(dataScad)
                .setCanOverflowOrderQuantity(false)
                .setCanLUBeClosed(false)
                .setCanPartitaMagBeChanged(false);

        DialogInputQuantityV2View
                .newInstance(dialogInputQuantityV2DTO, (resultDTO, shouldCloseLU) -> {
                    PickedQuantityDTO pickedQuantityDTO = new PickedQuantityDTO()
                            .setNumCnf(resultDTO.getNumCnf())
                            .setQtaCnf(resultDTO.getQtaCnf())
                            .setQtaTot(resultDTO.getQtaTot())
                            .setPartitaMag(resultDTO.getPartitaMag())
                            .setDataScad(resultDTO.getDataScad());

                    this.openProgress();
                    onComplete.run(pickedQuantityDTO, shouldCloseLU);
                }, () -> {
                    this.mViewmodel.resetMatchedRows();
                })
                .show(getSupportFragmentManager(), "tag");
    }

    @Override
    public void onFilterApplied(String newValue) {
        this.mBindings.filteredArtsInListExpandableLayout.expand(true);
        this.mBindings.descriptionFilterText.setText(!UtilityString.isNullOrEmpty(newValue) ? newValue : "");
    }

    @Override
    public void onFilterRemoved() {
        this.mBindings.filteredArtsInListExpandableLayout.collapse(true);
        this.mBindings.descriptionFilterText.setText("");
    }

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

    @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(getSupportFragmentManager(), "tag");
    }

    @Override
    public void onLUOpened(MtbColt mtbColt) {
        noLUPresent.set(false);
        FBToast.successToast(this, getResources().getString(R.string.data_saved), FBToast.LENGTH_SHORT);

        this.mBottomSheetFragmentLUContentViewModel.setMtbColt(mtbColt);
    }

    @Override
    public void onLUClosed() {
        noLUPresent.set(true);
        this.mBottomSheetFragmentLUContentViewModel.setMtbColt(null);

        if (this.mShouldCloseActivity) super.onBackPressed();
    }

    @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(getSupportFragmentManager(), "tag");
    }

    @Override
    public void onLUPrintRequest(RunnableArgs<Boolean> onComplete) {
        DialogAskShouldPrint.make(this, "Packing List", onComplete).show();
    }

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

    @Override
    public void onLoadingStarted() {
        this.openProgress();
    }

    @Override
    public void onLoadingEnded() {
        this.closeProgress();
    }
}
