package it.integry.integrywmsnative.gest.prod_rientro_merce.order_detail;

import androidx.lifecycle.MutableLiveData;

import com.annimon.stream.Optional;
import com.annimon.stream.Stream;

import java.util.Date;
import java.util.HashMap;
import java.util.List;

import javax.inject.Inject;

import it.integry.integrywmsnative.core.expansion.RunnableArgs;
import it.integry.integrywmsnative.core.interfaces.viewmodel_listeners.ILoadingListener;
import it.integry.integrywmsnative.core.model.MtbColt;
import it.integry.integrywmsnative.core.report.ReportType;
import it.integry.integrywmsnative.core.rest.consumers.ColliMagazzinoRESTConsumer;
import it.integry.integrywmsnative.core.rest.consumers.PrinterRESTConsumer;
import it.integry.integrywmsnative.core.settings.SettingsManager;
import it.integry.integrywmsnative.core.utility.UtilityDate;
import it.integry.integrywmsnative.gest.prod_rientro_merce.order_detail.rest.ProdRientroMerceOrderDetailRESTConsumer;
import it.integry.integrywmsnative.gest.prod_rientro_merce.order_detail.rest.dto.ImportColliDaProduzioneRequestDTO;
import it.integry.integrywmsnative.gest.prod_versamento_materiale.dto.OrdineLavorazioneDTO;
import it.integry.integrywmsnative.view.dialogs.printSsccUl.dto.PrintUlDTO;

public class ProdRientroMerceOrderDetailViewModel {

    public final MutableLiveData<List<MtbColt>> mtbColtsOfOrder = new MutableLiveData<>();
    private OrdineLavorazioneDTO currentOrder;

    private final ProdRientroMerceOrderDetailRESTConsumer mProdRientroMerceOrderDetailRESTConsumer;
    private final ColliMagazzinoRESTConsumer mColliMagazzinoRESTConsumer;
    private final PrinterRESTConsumer mPrinterRESTConsumer;

    private Listener mListener;

    @Inject
    public ProdRientroMerceOrderDetailViewModel(ProdRientroMerceOrderDetailRESTConsumer prodRientroMerceOrderDetailRESTConsumer,
                                                ColliMagazzinoRESTConsumer colliMagazzinoRESTConsumer,
                                                PrinterRESTConsumer printerRESTConsumer) {
        this.mProdRientroMerceOrderDetailRESTConsumer = prodRientroMerceOrderDetailRESTConsumer;
        this.mColliMagazzinoRESTConsumer = colliMagazzinoRESTConsumer;
        this.mPrinterRESTConsumer = printerRESTConsumer;
    }

    public void setOrder(OrdineLavorazioneDTO order) {
        this.currentOrder = order;

        refreshMtbColts();
    }

    public void refreshMtbColts() {
        this.sendOnLoadingStarted();
        this.mtbColtsOfOrder.postValue(null);

        this.mProdRientroMerceOrderDetailRESTConsumer.getMtbColtsOfOrder(currentOrder, mtbColts -> {
            for (MtbColt mtbColt : mtbColts) {
                mtbColt.getMtbColr().get(0)
                        .setDescrizione(currentOrder.getDescrizioneProd())
                        .setUntMis(currentOrder.getUntOrd());
            }

            this.mtbColtsOfOrder.postValue(mtbColts);
            this.sendOnLoadingEnded();
        }, this::sendError);
    }

    public void createLU(ProdRientroMerceOrderDetailPickedQuantityDTO pickedQuantityDTO) {

        new Thread(this::sendOnLoadingStarted).start();

        new Thread(() -> {

            ImportColliDaProduzioneRequestDTO importColliDaProduzioneRequestDTO =
                    new ImportColliDaProduzioneRequestDTO()
                            .setColliBancale(pickedQuantityDTO.getNumCnf().intValue())
                            .setQtaCnf(pickedQuantityDTO.getPesoCollo())
                            .setQtaCol(pickedQuantityDTO.getPesoNetto())
                            .setCodJcom(currentOrder.getCodJcom())
                            .setCodJfas(pickedQuantityDTO.getJtbFasi() != null ? pickedQuantityDTO.getJtbFasi().getCodJfas() : null)
                            .setCodMart(currentOrder.getCodProd())
                            .setCodTcol(pickedQuantityDTO.getMtbTCol() != null ? pickedQuantityDTO.getMtbTCol().getCodTcol() : null)
                            .setDataCollo(new Date())
                            .setDataOrd(currentOrder.getDataOrdD())
                            .setNumOrd(currentOrder.getNumOrd())
                            .setGestione(currentOrder.getGestione())
                            .setPartitaMag(currentOrder.getPartitaMag())
                            .setFornitore(currentOrder.getRagSocAnag())
                            .setPesoLordo(pickedQuantityDTO.getPesoLordo())
                            .setPesoNetto(pickedQuantityDTO.getPesoNetto());

            this.mProdRientroMerceOrderDetailRESTConsumer.importColloDaProduzione(importColliDaProduzioneRequestDTO, mtbColtSaved -> {
                synchronized (this.mtbColtsOfOrder) {
                    this.mListener.onDataSaved(mtbColtSaved);
                }
            }, this::sendError);


        }).start();

    }

    public void deleteLU(MtbColt mtbColt) {
        new Thread(this::sendOnLoadingStarted).start();

        new Thread(() -> {
            this.mProdRientroMerceOrderDetailRESTConsumer.deleteColloDaProduzione(mtbColt, () -> {
                synchronized (this.mtbColtsOfOrder) {
                    Optional<MtbColt> mtbColtToRemove = Stream.of(this.mtbColtsOfOrder.getValue())
                            .filter(x -> x.getNumCollo().equals(mtbColt.getNumCollo()) &&
                                    x.getSerCollo().equalsIgnoreCase(mtbColt.getSerCollo()) &&
                                    x.getDataColloD().compareTo(mtbColt.getDataColloD()) == 0 &&
                                    x.getGestione().equalsIgnoreCase(mtbColt.getGestione()))
                            .findFirst();

                    if (mtbColtToRemove.isPresent()) {
                        this.mtbColtsOfOrder.getValue().remove(mtbColtToRemove.get());
                        this.mtbColtsOfOrder.postValue(this.mtbColtsOfOrder.getValue());
                    }

                }

                this.sendOnLoadingEnded();
            }, this::sendError);
        }).start();
    }

    public void setListener(Listener listener) {
        this.mListener = listener;
    }


    private void sendOnLoadingStarted() {
        if (this.mListener != null) mListener.onLoadingStarted();
    }

    private void sendOnLoadingEnded() {
        if (this.mListener != null) mListener.onLoadingEnded();
    }

    private void sendError(Exception ex) {
        if (this.mListener != null) mListener.onError(ex);
    }

    public void printSavedMtbColt(PrintUlDTO result) {
        if (result.isFlagPrintProductionLabel()) {
            this.startPrint(result.getMtbColt(), ReportType.ETICHETTA_SSCC_LAVORAZIONE, currentOrder.getCodAnag());
        } else {
            this.loadShipmentUlFromProductionUL(result.getMtbColt(), mtbColt -> {
                this.startPrint(mtbColt, ReportType.ETICHETTA_SSCC_SPEDIZIONE, mtbColt.getCodAnag());
            }, this::sendError);
        }

    }

    private void loadShipmentUlFromProductionUL(MtbColt productionUL, RunnableArgs<MtbColt> onLoad, RunnableArgs<Exception> onError) {
        this.mColliMagazzinoRESTConsumer.loadShipmentUlFromProductionUL(productionUL, onLoad, onError);
    }

    private void startPrint(MtbColt mtbColt, ReportType reportType, String codAnag) {
        HashMap<String, Object> params = new HashMap<>();
        params.put("gestione", mtbColt.getGestione());
        params.put("ser_collo", mtbColt.getSerCollo());
        params.put("num_collo", mtbColt.getNumCollo());
        params.put("data_collo", UtilityDate.formatDate(mtbColt.getDataColloD(), UtilityDate.COMMONS_DATE_FORMATS.YMD_DASH));
        this.mPrinterRESTConsumer.printReportType(
                reportType,
                SettingsManager.i().getUserSession().getDepo().getCodMdep(),
                codAnag,
                params,
                this::refreshMtbColts,
                this::sendError);
    }

    public interface Listener extends ILoadingListener {

        void onDataSaved(MtbColt mtbColt);

        void onError(Exception ex);

    }
}
