package it.integry.integrywmsnative.gest.prod_dettaglio_linea;

import androidx.lifecycle.MutableLiveData;

import javax.inject.Inject;

import it.integry.barcode_base_android_library.model.BarcodeScanDTO;
import it.integry.integrywmsnative.core.barcode_reader.BarcodeManager;
import it.integry.integrywmsnative.core.exception.NoLUFoundException;
import it.integry.integrywmsnative.core.expansion.RunnableArgs;
import it.integry.integrywmsnative.core.interfaces.viewmodel_listeners.ILoadingListener;
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.rest.consumers.BarcodeRESTConsumer;
import it.integry.integrywmsnative.core.rest.consumers.ColliMagazzinoRESTConsumer;
import it.integry.integrywmsnative.core.rest.consumers.MesRESTConsumer;
import it.integry.integrywmsnative.core.rest.consumers.ProductionLinesRESTConsumer;
import it.integry.integrywmsnative.core.utility.UtilityBarcode;
import it.integry.integrywmsnative.core.utility.UtilityString;
import it.integry.integrywmsnative.gest.prod_linee_produzione.dto.ProdLineStatusDTO;
import it.integry.integrywmsnative.gest.spedizione.model.PickedQuantityDTO;

public class ProdDettaglioLineaViewModel {

    private Listener mListener;

    private final ProductionLinesRESTConsumer productionLinesRESTConsumer;
    private final ColliMagazzinoRESTConsumer colliMagazzinoRESTConsumer;
    private final MesRESTConsumer mesRESTConsumer;
    private final BarcodeRESTConsumer mBarcodeRESTConsumer;
    public final MutableLiveData<ProdLineStatusDTO> lineaProd = new MutableLiveData<>();


    @Inject
    public ProdDettaglioLineaViewModel(ProductionLinesRESTConsumer productionLinesRESTConsumer, BarcodeRESTConsumer barcodeRESTConsumer, ColliMagazzinoRESTConsumer magazzinoRESTConsumer, MesRESTConsumer mesRESTConsumer) {
        this.productionLinesRESTConsumer = productionLinesRESTConsumer;
        this.mBarcodeRESTConsumer = barcodeRESTConsumer;
        this.colliMagazzinoRESTConsumer = magazzinoRESTConsumer;
        this.mesRESTConsumer = mesRESTConsumer;
    }

    public void processBarcodeDTO(BarcodeScanDTO barcodeScanDTO, Runnable onComplete) {
        if (UtilityBarcode.isEtichettaAnonima(barcodeScanDTO)) {
            this.executeEtichettaAnonima(barcodeScanDTO, onComplete);
        } else if (UtilityBarcode.isEtichetta128(barcodeScanDTO)) {
            this.executeEAN128(barcodeScanDTO, onComplete);
        } else {
            onComplete.run();
        }
    }

    private void executeEtichettaAnonima(BarcodeScanDTO barcodeScanDTO, Runnable onComplete) {
        handleSSCCBarcode(barcodeScanDTO.getStringValue(), onComplete);
    }

    private void handleSSCCBarcode(String sscc, Runnable onComplete) {
        this.colliMagazzinoRESTConsumer.getBySSCC(sscc, true, false, mtbColt -> {

            if (mtbColt == null) {
                this.sendError(new NoLUFoundException());
            } else {
                if (mtbColt.getMtbColr().size() <= 0) {
                    this.sendError(new Exception("E' stata scansionata una UL già vuota"));
                } else {
                    this.sendOnLUSelected(mtbColt);
                }
            }
        }, this::sendError);
    }

    private void sendOnLUSelected(MtbColt mtbColt) {
        this.sendOnLoadingStarted();
        this.checkOrdersCompatibility(mtbColt, () -> {
            MtbColr row = mtbColt.getMtbColr().get(0);
            mListener.requestQtaVersamento(
                    row,
                    dto -> {
                        sendOnLoadingStarted();
                        row.setQtaCnf(dto.getQtaCnf());
                        row.setNumCnf(dto.getNumCnf());
                        row.setQtaCol(dto.getQtaTot());
                        row.setPesoLordoKg(null);
                        row.setPesoNettoKg(null);
                        ProdLineStatusDTO prodLine = lineaProd.getValue();
                        MtbDepoPosizione posizione = new MtbDepoPosizione();
                        posizione.setPosizione(prodLine.getCodJfas());
                        posizione.setCodMdep(prodLine.getCodMdepLav());
                        posizione.setFlagLineaProduzione("S");
                        this.colliMagazzinoRESTConsumer.createColloScaricoDaCarico(mtbColt, posizione,
                                generatedMtbColt -> {
                                    this.sendOnLoadingEnded();
                                    this.mListener.showToast("Versamento completato!", BarcodeManager::enable);
                                }, this::sendError);
                    });
        });
    }

    private void checkOrdersCompatibility(MtbColt mtbColt, Runnable onComplete) {
        mesRESTConsumer.getOrdiniLavorazioneMateriale(lineaProd.getValue().getCodJfas(), getIdMaterialeFromCollo(mtbColt), ordini -> {
            if (ordini != null && ordini.size() > 0) {
                onComplete.run();
            } else {
                this.mListener.confirmInconsistentDeposit(onComplete);
            }
        }, this::sendError);
    }

    private String getIdMaterialeFromCollo(MtbColt mtbColt) {
        MtbAart articolo = mtbColt.getMtbColr().get(0).getMtbAart();
        return UtilityString.isNullOrEmpty(articolo.getIdArtEqui()) ? articolo.getCodMart() : articolo.getIdArtEqui();
    }


    private void executeEAN128(BarcodeScanDTO barcodeScanDTO, Runnable onComplete) {
        this.mBarcodeRESTConsumer.decodeEan128(barcodeScanDTO, ean128Model -> {
            if (ean128Model != null && !UtilityString.isNullOrEmpty(ean128Model.Sscc)) {
                handleSSCCBarcode(ean128Model.Sscc, onComplete);
            } else {
                this.sendError(new NoLUFoundException());
            }

        }, this::sendError);
    }

    public void settings() {
        this.mListener.onSettingsRequest(lineaProd.getValue());
    }

    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 startProductionLine(Integer hrNum) {
        this.sendOnLoadingStarted();
        ProdLineStatusDTO prodLine = lineaProd.getValue();
        this.productionLinesRESTConsumer.avviaLineaDiProduzione(prodLine.getCodJfas(),
                hrNum,
                () -> this.mListener.successDialog("Operazione completata", this::loadLineDetails),
                this::sendError);
    }


    private void startProduction(String codMart, String partitaMag) {
        this.sendOnLoadingStarted();
        ProdLineStatusDTO prodLine = lineaProd.getValue();
        this.productionLinesRESTConsumer.avviaProduzioneArticoloSuLinea(prodLine.getCodJfas(), codMart, partitaMag,
                () -> this.mListener.successDialog("Operazione completata", this::loadLineDetails),
                this::sendError);
    }

    public void stopProduction() {
        this.sendOnLoadingStarted();
        ProdLineStatusDTO prodLine = lineaProd.getValue();
        this.productionLinesRESTConsumer.arrestaLineaDiProduzione(prodLine.getCodJfas(),
                () -> this.mListener.successDialog("Operazione completata", this::onLineStop),
                this::sendError);
    }

    private void onLineStop() {
        this.mListener.onLineStop();
    }

    public void checkBarcodeAndStartOrdine(BarcodeScanDTO dto) {
        this.sendOnLoadingStarted();
        ProdLineStatusDTO prodLine = lineaProd.getValue();
        mBarcodeRESTConsumer.decodeEan128(dto, (ean128) -> {
            String codMart = ean128.Content;
            String partitaMag = ean128.BatchLot;
            if (!prodLine.isStarted()) {
                this.sendError(new Exception("Impossibile avviare una produzione su una linea ferma!"));
            } else if (UtilityString.isNullOrEmpty(prodLine.getListaOrd())) {
                this.startProduction(codMart, partitaMag);
            } else {
                this.mListener.confirmOrderClose(() -> {
                    this.startProduction(codMart, partitaMag);
                });
            }
        }, this::sendError);
    }

    public void loadLineDetails() {
        sendOnLoadingStarted();
        if (lineaProd.getValue() == null) {
            this.sendError(new Exception("Nessuna linea selezionata!"));
            return;
        }
        productionLinesRESTConsumer.getLineDetails(lineaProd.getValue(), linea -> {
            this.lineaProd.postValue(linea);
            sendOnLoadingEnded();
        }, this::sendError);
    }

    public void init(ProdLineStatusDTO lineaProd) {
        this.lineaProd.setValue(lineaProd);
        this.loadLineDetails();
    }

    public ProdLineStatusDTO getLineaProd() {
        return lineaProd.getValue();
    }


    public interface Listener extends ILoadingListener {
        void onError(Exception ex);

        void successDialog(String message, Runnable onComplete);

        void showToast(String message, Runnable onComplete);

        void requestQtaVersamento(MtbColr mtbColr, RunnableArgs<PickedQuantityDTO> onComplete);

        void onSettingsRequest(ProdLineStatusDTO lineaProd);

        void confirmInconsistentDeposit(Runnable onConfirm);

        void onLineStop();

        void confirmOrderClose(Runnable onConfirm);
    }

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

}
