package it.integry.integrywmsnative.gest.prod_versamento_materiale;

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

import androidx.appcompat.widget.AppCompatTextView;
import androidx.databinding.ObservableArrayList;
import androidx.databinding.ObservableField;
import androidx.recyclerview.widget.LinearLayoutManager;

import com.annimon.stream.Stream;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.time.LocalDate;
import java.util.List;

import javax.inject.Inject;

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.BindableString;
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.ITitledFragment;
import it.integry.integrywmsnative.core.model.MtbAart;
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.UtilityBigDecimal;
import it.integry.integrywmsnative.core.utility.UtilityDate;
import it.integry.integrywmsnative.core.utility.UtilityNumber;
import it.integry.integrywmsnative.core.utility.UtilityResources;
import it.integry.integrywmsnative.core.utility.UtilityString;
import it.integry.integrywmsnative.databinding.FragmentProdVersamentoMaterialeBinding;
import it.integry.integrywmsnative.gest.prod_versamento_materiale.dto.OrdineLavorazioneDTO;
import it.integry.integrywmsnative.gest.prod_versamento_materiale.dto.VersamentoMerceOrdineLavListModel;
import it.integry.integrywmsnative.gest.prod_versamento_materiale.ui.ChooseOrdsLavFromListAdapter;
import it.integry.integrywmsnative.gest.spedizione.model.PickedQuantityDTO;
import it.integry.integrywmsnative.gest.spedizione.model.PickingObjectDTO;
import it.integry.integrywmsnative.view.dialogs.DialogCommon;
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.input_quantity_v2.DialogInputQuantityV2DTO;
import it.integry.integrywmsnative.view.dialogs.input_quantity_v2.DialogInputQuantityV2View;

public class ProdVersamentoMaterialeFragment extends BaseFragment implements ProdVersamentoMaterialeViewModel.Listener, ITitledFragment {

    @Inject
    ProdVersamentoMaterialeViewModel mViewModel;

    @Inject
    DialogInputQuantityV2View mDialogInputQuantityV2View;

    private FragmentProdVersamentoMaterialeBinding mBinding;

    private final ObservableField<MtbColt> mCurrentMtbColt = new ObservableField<>();
    private final ObservableField<Boolean> mCurrentMtbColtSet = new ObservableField<>(false);
    private final ObservableArrayList<VersamentoMerceOrdineLavListModel> mCurrentOrders = new ObservableArrayList<>();

    public final BindableString codPrimaryArt = new BindableString();
    public final BindableString descrizionePrimaryArt = new BindableString();
    public final BindableString lottoPrimaryArt = new BindableString();
    public final BindableString quantityPrimaryArt = new BindableString();
    public final ObservableField<Boolean> fabVisible = new ObservableField<>(false);


    private int barcodeScannerIstanceID = -1;

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

    public static ProdVersamentoMaterialeFragment newInstance() {
        return new ProdVersamentoMaterialeFragment();
    }

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
                             Bundle savedInstanceState) {
        // Inflate the layout for this fragment
        setRetainInstance(true);
        mBinding = FragmentProdVersamentoMaterialeBinding.inflate(inflater, container, false);

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

        this.mViewModel.setListener(this);

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

        return mBinding.getRoot();
    }


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

        this.mViewModel.init(SettingsManager.iDB().isFlagVersamentoDirettoProduzione());

        this.initView();
        this.initBarcodeReader();
    }

    private void initView() {
        this.mViewModel.getOpenedOrderLavMutableLiveList().observe(getViewLifecycleOwner(), this::refreshList);
        this.mViewModel.getMtbColtMutableLiveData().observe(getViewLifecycleOwner(), value -> {
            this.mCurrentMtbColt.set(value);
            this.mCurrentMtbColtSet.set(true);
        });

        this.mViewModel.getMtbColrMutableLiveData().observe(getViewLifecycleOwner(), firstMtbColr -> {
            codPrimaryArt.set(firstMtbColr.getCodMart());
            descrizionePrimaryArt.set(firstMtbColr.getDescrizione());
            lottoPrimaryArt.set(firstMtbColr.getPartitaMag() + ((firstMtbColr.getMtbPartitaMag() != null) ? " - " + firstMtbColr.getMtbPartitaMag().getDescrizione() : ""));

            if (!SettingsManager.iDB().isFlagForceAllToColli() && (firstMtbColr.getMtbAart() == null || firstMtbColr.getMtbAart().isFlagQtaCnfFissaBoolean())) {
                String text = UtilityNumber.decimalToString(firstMtbColr.getQtaCol());

                if (firstMtbColr.getMtbAart() != null) {
                    text += !UtilityString.isNullOrEmpty(firstMtbColr.getMtbAart().getUntMis()) ? " " + firstMtbColr.getMtbAart().getUntMis() : "";
                }

                quantityPrimaryArt.set(text);
            } else {
                quantityPrimaryArt.set(UtilityNumber.decimalToString(firstMtbColr.getNumCnf()) + " " + UtilityResources.getString(R.string.unt_mis_col));
            }
        });

        initRecyclerView();

    }


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

        ChooseOrdsLavFromListAdapter adapter = new ChooseOrdsLavFromListAdapter(
                requireActivity(),
                this.mCurrentOrders,
                SettingsManager.iDB().isFlagForceAllToColli())
                .setOnItemClickListener(clickedItem -> {
                    recalcAllQuantities();
                });
        adapter.setEmptyView(mBinding.emptyView);
        mBinding.listaArts.setAdapter(adapter);
    }

    private void refreshList(List<OrdineLavorazioneDTO> orders) {
        this.mCurrentOrders.clear();
        this.mCurrentOrders.addAll(convertDataModelToListModel(orders));
    }

    private List<VersamentoMerceOrdineLavListModel> convertDataModelToListModel(List<OrdineLavorazioneDTO> dataList) {

        return Stream.of(dataList)
                .withoutNulls()
                .map(x -> {
                    VersamentoMerceOrdineLavListModel listModel = new VersamentoMerceOrdineLavListModel();

                    listModel.setOriginalOrdineLavorazione(x);
                    listModel.setOriginalMtbAart(this.mViewModel.getMtbColrMutableLiveData().getValue().getMtbAart());

                    listModel.setPreDescriptionText(
                            getString(R.string.ord_testata, String.valueOf(x.getNumOrd()), UtilityDate.formatDate(x.getDataOrdD(), UtilityDate.COMMONS_DATE_FORMATS.DMY_HUMAN)));

                    listModel.setDescriptionText(x.getCodProd() + " " + x.getDescrizioneProd());

                    listModel.setSubDescriptionText(UtilityString.isNullOrEmpty(x.getPartitaMag()) ? "" : getString(R.string.batch_lot_text, x.getPartitaMag()));

                    listModel.setSubDescription2Text(UtilityString.isNullOrEmpty(x.getNoteLav()) ? "" : getString(R.string.notes_text, x.getNoteLav()));

                    return listModel;
                })
                .toList();
    }


    private void initBarcodeReader() {
        barcodeScannerIstanceID = BarcodeManager.addCallback(new BarcodeCallbackDTO()
                .setOnScanSuccessful(mViewModel::processBarcodeDTO)
                .setOnScanFailed(this::onError));

        BarcodeManager.enable();
    }

//    private void openLU() {
//        DialogScanOrCreateLUView.newInstance(false, false, true, false, true, (mtbColt, created) -> {
//            if (mtbColt == null) {
//                popMe();
//            } else if ((mtbColt.getGestioneEnum() == GestioneEnum.ACQUISTO || mtbColt.getGestioneEnum() == GestioneEnum.LAVORAZIONE || mtbColt.getGestioneEnum() == GestioneEnum.VENDITA) && mtbColt.getSegno().equals(+1)) {
//
//                if (mtbColt.getMtbColr() == null || mtbColt.getMtbColr().size() == 0) {
//                    DialogSimpleMessageView.makeWarningDialog(
//                                    new SpannableString(Html.fromHtml("E' stata scansionata una UL già vuota")),
//                                    null, this::openLU)
//                            .show((requireActivity()).getSupportFragmentManager(), "tag");
//
//                } else {
//                    mViewModel.setMtbColt(mtbColt);
//                    choosePosition();
//                }
//
//            } else {
//                this.onError(new Exception("Sono accettate solamente UL di <b>Acquisto</b> o <b>Lavorazione</b> di <b>CARICO</b>"));
//            }
//        }).show(requireActivity().getSupportFragmentManager(), "tag");
//    }

    private void choosePosition(RunnableArgs<MtbDepoPosizione> onComplete) {
        DialogAskPositionOfLUView.makeBase(false, (status, mtbDepoPosizione) -> {

                    if (status == DialogConsts.Results.ABORT) {
                        popMe();
                    } else {
                        onComplete.run(mtbDepoPosizione);
                    }

                }, this::onError)
                .show(requireActivity().getSupportFragmentManager(), "tag");
    }


    private void recalcAllQuantities() {
        if (this.mViewModel.getMtbColrMutableLiveData().getValue() == null) return;

        BigDecimal residuoCol = this.mViewModel.getMtbColrMutableLiveData().getValue().getQtaCol();
        BigDecimal residuoCnf = this.mViewModel.getMtbColrMutableLiveData().getValue().getNumCnf();
        BigDecimal qtaCnf = this.mViewModel.getMtbColrMutableLiveData().getValue().getQtaCnf();

        BigDecimal offsetCol = BigDecimal.ZERO.add(residuoCol); //Forced clone
        BigDecimal offsetCnf = BigDecimal.ZERO.add(residuoCnf); //Forced clone

        List<VersamentoMerceOrdineLavListModel> selectedOrders = Stream.of(this.mCurrentOrders)
                .filter(x -> x.getSelected().get())
                .toList();

        int totalHr = Stream.of(selectedOrders)
                .mapToInt(x -> x.getOriginalOrdineLavorazione().getHrNum())
                .sum();

        if (selectedOrders.size() > 0 && totalHr <= 0) {
            this.onError(new Exception("Il totale delle <b>risorse umane</b> è pari a 0"));
            return;
        }

        fabVisible.set(selectedOrders.size() > 0);

        for (VersamentoMerceOrdineLavListModel versamentoMerceOrdineLavListModel : this.mCurrentOrders) {
            versamentoMerceOrdineLavListModel.setNumCnfBigDecimal(BigDecimal.ZERO);
            versamentoMerceOrdineLavListModel.setQtaBigDecimal(BigDecimal.ZERO);

            versamentoMerceOrdineLavListModel.getOriginalOrdineLavorazione().setQtaColVersamento(0f);
            versamentoMerceOrdineLavListModel.getOriginalOrdineLavorazione().setNumCnfVersamento(0f);
        }

        for (VersamentoMerceOrdineLavListModel versamentoMerceOrdineLavListModel : selectedOrders) {
            int usagePerc = (versamentoMerceOrdineLavListModel.getOriginalOrdineLavorazione().getHrNum() * 100) / totalHr;
            BigDecimal usedCol;
            BigDecimal usedCnf;

            if (SettingsManager.iDB().isFlagForceAllToColli() || (versamentoMerceOrdineLavListModel.getOriginalMtbAart() != null && !versamentoMerceOrdineLavListModel.getOriginalMtbAart().isFlagQtaCnfFissaBoolean())) {
                usedCnf = UtilityBigDecimal.divideAndRoundToInteger(residuoCnf.multiply(BigDecimal.valueOf(usagePerc)), BigDecimal.valueOf(100), RoundingMode.FLOOR);

                if (UtilityBigDecimal.equalsOrLowerThan(usedCnf, BigDecimal.ZERO) && UtilityBigDecimal.greaterThan(offsetCnf, BigDecimal.ZERO)) {
                    usedCnf = BigDecimal.ONE;
                }

                usedCol = usedCnf.multiply(qtaCnf).setScale(0, BigDecimal.ROUND_FLOOR);
            } else {
                usedCol = UtilityBigDecimal.divideAndRoundToInteger(residuoCol.multiply(BigDecimal.valueOf(usagePerc)), BigDecimal.valueOf(100), RoundingMode.FLOOR);

                if (UtilityBigDecimal.equalsOrLowerThan(usedCol, BigDecimal.ZERO) && UtilityBigDecimal.greaterThan(offsetCol, BigDecimal.ZERO)) {
                    usedCol = BigDecimal.ONE;
                }

                usedCnf = UtilityBigDecimal.divide(usedCol, qtaCnf, RoundingMode.FLOOR);
            }

            offsetCol = offsetCol.subtract(usedCol);
            offsetCnf = offsetCnf.subtract(usedCnf);

            versamentoMerceOrdineLavListModel.setNumCnfBigDecimal(usedCnf);
            versamentoMerceOrdineLavListModel.setQtaBigDecimal(usedCol);

            versamentoMerceOrdineLavListModel.getOriginalOrdineLavorazione().setQtaColVersamento(usedCol.floatValue());
            versamentoMerceOrdineLavListModel.getOriginalOrdineLavorazione().setNumCnfVersamento(usedCnf.floatValue());
        }


        if (selectedOrders.size() > 0) {
            VersamentoMerceOrdineLavListModel majorOrder =
                    Stream.of(selectedOrders)
                            .max((o1, o2) -> Integer.compare(o1.getOriginalOrdineLavorazione().getHrNum(), o2.getOriginalOrdineLavorazione().getHrNum())).get();

            if (offsetCnf.floatValue() != 0 || offsetCol.floatValue() != 0) {
                if (SettingsManager.iDB().isFlagForceAllToColli() || (majorOrder.getOriginalMtbAart() != null && !majorOrder.getOriginalMtbAart().isFlagQtaCnfFissaBoolean())) {
                    majorOrder.setNumCnfBigDecimal(majorOrder.getNumCnfBigDecimal().add(offsetCnf));
                    majorOrder.getOriginalOrdineLavorazione().setNumCnfVersamento(majorOrder.getNumCnfBigDecimal().floatValue());

                    majorOrder.setQtaBigDecimal(majorOrder.getQtaBigDecimal().add(offsetCol));
                    majorOrder.getOriginalOrdineLavorazione().setQtaColVersamento(majorOrder.getQtaBigDecimal().floatValue());
                } else {
                    majorOrder.setQtaBigDecimal(majorOrder.getQtaBigDecimal().add(offsetCol));
                    majorOrder.getOriginalOrdineLavorazione().setQtaColVersamento(majorOrder.getQtaBigDecimal().floatValue());

                    majorOrder.setNumCnfBigDecimal(UtilityBigDecimal.divide(majorOrder.getQtaBigDecimal(), qtaCnf));
                    majorOrder.getOriginalOrdineLavorazione().setNumCnfVersamento(majorOrder.getNumCnfBigDecimal().floatValue());
                }
            }
        }
    }


    public void onConfirmClicked() {
        List<OrdineLavorazioneDTO> selectedOrders = Stream.of(this.mCurrentOrders)
                .filter(x -> x.getSelected().get())
                .map(VersamentoMerceOrdineLavListModel::getOriginalOrdineLavorazione)
                .toList();

        if (selectedOrders.size() > 0) {
            this.mViewModel.save(selectedOrders);
        } else {
            Toast.makeText(requireActivity(), "Nessun ordine selezionato!", Toast.LENGTH_SHORT).show();
        }
    }




    public ObservableField<Boolean> isCurrentMtbColtSettedObservable() {
        return mCurrentMtbColtSet;
    }

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

    @Override
    public void requestLUOpen() {
//        this.openLU();
    }

    @Override
    public void onRequestChoosePosition(RunnableArgs<MtbDepoPosizione> onComplete) {
        choosePosition(onComplete);
    }

    @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, LocalDate dataScad, boolean canOverflowOrderQuantity, boolean canPartitaMagBeChanged, 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);

        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 onError(Exception ex, boolean requestClose) {
        super.onError(ex);
        if (requestClose) popMe();
    }

    @Override
    public void onWarning(String warningText, Runnable action) {
        this.requireActivity().runOnUiThread(() -> {
            this.onLoadingEnded();
            DialogSimpleMessageView
                    .makeWarningDialog(new SpannableString(Html.fromHtml(warningText)), null, action)
                    .show(requireActivity().getSupportFragmentManager(), "tag");
        });
    }

    @Override
    public void onDataSaved() {
        this.onLoadingEnded();
        this.requireActivity().runOnUiThread(() -> {
            DialogCommon.showDataSaved(requireActivity(), this::popMe);
        });
    }

}
