package it.integry.integrywmsnative.core.rest.consumers;

import androidx.databinding.ObservableArrayList;

import com.annimon.stream.Optional;
import com.annimon.stream.Stream;
import com.google.gson.Gson;
import com.google.gson.JsonObject;
import com.google.gson.reflect.TypeToken;

import org.jetbrains.annotations.NotNull;

import java.lang.reflect.Type;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;

import javax.inject.Singleton;

import it.integry.barcode_base_android_library.model.BarcodeScanDTO;
import it.integry.integrywmsnative.core.CommonConst;
import it.integry.integrywmsnative.core.expansion.RunnableArgs;
import it.integry.integrywmsnative.core.model.CommonModelConsts;
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.model.secondary.GestioneEnum;
import it.integry.integrywmsnative.core.rest.RESTBuilder;
import it.integry.integrywmsnative.core.rest.model.DistribuzioneColloDTO;
import it.integry.integrywmsnative.core.rest.model.RettificaULDTO;
import it.integry.integrywmsnative.core.rest.model.ServiceRESTResponse;
import it.integry.integrywmsnative.core.rest.model.SpostaArtsTraULRequestDTO;
import it.integry.integrywmsnative.core.rest.model.VersamentoAutomaticoULResponseDTO;
import it.integry.integrywmsnative.core.settings.SettingsManager;
import it.integry.integrywmsnative.core.utility.UtilityBarcode;
import it.integry.integrywmsnative.core.utility.UtilityDate;
import it.integry.integrywmsnative.core.utility.UtilityQuery;
import it.integry.integrywmsnative.core.utility.UtilityString;
import it.integry.integrywmsnative.gest.prod_versamento_materiale.dto.OrdineLavorazioneDTO;
import retrofit2.Call;
import retrofit2.Callback;
import retrofit2.Response;

@Singleton
public class ColliMagazzinoRESTConsumer extends _BaseRESTConsumer {

    private final SystemRESTConsumer mSystemRESTConsumer;
    private final ArticoloRESTConsumer mArticoloRESTConsumer;
    private final EntityRESTConsumer mEntityRESTConsumer;

    public ColliMagazzinoRESTConsumer(SystemRESTConsumer systemRESTConsumer,
                                      ArticoloRESTConsumer articoloRESTConsumer,
                                      EntityRESTConsumer entityRESTConsumer) {
        this.mSystemRESTConsumer = systemRESTConsumer;
        this.mArticoloRESTConsumer = articoloRESTConsumer;
        this.mEntityRESTConsumer = entityRESTConsumer;
    }

    public void saveCollo(MtbColt mtbColtToSave, RunnableArgs<MtbColt> onComplete, RunnableArgs<Exception> onFailed) {
        MtbColt mtbColtToSaveClone = (MtbColt) mtbColtToSave.clone();
        mtbColtToSave.setOperation(CommonModelConsts.OPERATION.INSERT_OR_UPDATE);

        mtbColtToSaveClone.setMtbColr(new ObservableArrayList<>());

        for (int i = 0; i < mtbColtToSave.getMtbColr().size(); i++) {
            mtbColtToSaveClone.getMtbColr().add(
                    ((MtbColr) mtbColtToSave.getMtbColr().get(i).clone())
                            .setMtbAart(null)
                            .setMtbPartitaMag(null));
        }

        this.mEntityRESTConsumer.processEntity(mtbColtToSaveClone, new ISimpleOperationCallback<MtbColt>() {
            @Override
            public void onSuccess(MtbColt value) {
                if (onComplete != null) onComplete.run(value);
            }

            @Override
            public void onFailed(Exception ex) {
                if (onFailed != null) onFailed.run(ex);
            }
        }, MtbColt.class);

    }

    public void saveColli(List<MtbColt> mtbColtsToSave, RunnableArgs<List<MtbColt>> onComplete, RunnableArgs<Exception> onFailed) {

        for (MtbColt mtbColt : mtbColtsToSave) {
            mtbColt.setMtbCols(null);

            for (int i = 0; i < mtbColt.getMtbColr().size(); i++) {
                mtbColt.getMtbColr().get(i)
                        .setMtbAart(null)
                        .setMtbPartitaMag(null);
            }
        }

        this.mEntityRESTConsumer.processEntityList(mtbColtsToSave, true, MtbColt.class, onComplete, onFailed);

    }

    public void createColloLavorazione(int segno, RunnableArgs<MtbColt> onComplete, RunnableArgs<Exception> onFailed) {
        MtbColt mtbColtToCreate = new MtbColt()
                .setSegno(segno);

        mtbColtToCreate.initDefaultFields(GestioneEnum.LAVORAZIONE);

        mtbColtToCreate
                .setOperation(CommonModelConsts.OPERATION.INSERT);


        saveCollo(mtbColtToCreate, value -> {
            if (onComplete != null) onComplete.run(value);
        }, ex -> {
            if (onFailed != null) onFailed.run(ex);
        });
    }

    public void createColloScaricoDaCarico(MtbColt sourceMtbColt, MtbDepoPosizione posizione, RunnableArgs<MtbColt> onComplete, RunnableArgs<Exception> onFailed) {

        MtbColt newMtbColt = new MtbColt()
                .initDefaultFields(GestioneEnum.LAVORAZIONE)
                .setCodAnag(null)
                .setSegno(-1)
                .setCodTcol(sourceMtbColt.getCodTcol())
                .setPesoKg(sourceMtbColt.getPesoKg())
                .setPesoNettoKg(sourceMtbColt.getPesoNettoKg())
                .setLarghezzaCm(sourceMtbColt.getLarghezzaCm())
                .setLunghezzaCm(sourceMtbColt.getLunghezzaCm())
                .setAltezzaCm(sourceMtbColt.getAltezzaCm())
                .setCodMdep(sourceMtbColt.getCodMdep())
                .setDataVers(UtilityDate.getDateInstance())
                .setOraFinePrep(UtilityDate.getDateInstance());

        newMtbColt.setOperation(CommonModelConsts.OPERATION.INSERT);

        if (posizione != null) {
            newMtbColt
                    .setPosizione(posizione.getPosizione());

            if (posizione.isFlagLineaProduzione()) {
                newMtbColt
                        .setCodJfas(posizione.getPosizione());
            }
        }

        for (int i = 0; i < sourceMtbColt.getMtbColr().size(); i++) {

            MtbColr mtbColrClone = (MtbColr) sourceMtbColt.getMtbColr().get(i).clone();

            mtbColrClone
                    .setNumCollo(null)
                    .setDataCollo((String) null)
                    .setRiga(null)
                    .setGestione(GestioneEnum.LAVORAZIONE)

                    .setDataColloRif(sourceMtbColt.getDataColloD())
                    .setNumColloRif(sourceMtbColt.getNumCollo())
                    .setGestioneRif(sourceMtbColt.getGestione())
                    .setSerColloRif(sourceMtbColt.getSerCollo())

                    .setOperation(CommonModelConsts.OPERATION.INSERT);

            newMtbColt.getMtbColr().add(mtbColrClone);
        }


        saveCollo(newMtbColt, onComplete, onFailed);
    }

    public void createColliScaricoDaOrdineLavorazione(MtbColt sourceMtbColt, MtbColr sourceMtbColr, MtbDepoPosizione posizione, List<OrdineLavorazioneDTO> ordini, RunnableArgs<MtbColt> onComplete, RunnableArgs<Exception> onFailed) {

        MtbColt newMtbColt = new MtbColt()
                .initDefaultFields(GestioneEnum.LAVORAZIONE)
                .setCodAnag(null)
                .setSegno(-1)
                .setCodTcol(sourceMtbColt.getCodTcol())
//                .setPesoKg(sourceMtbColt.getPesoKg())
//                .setPesoNettoKg(sourceMtbColt.getPesoNettoKg())
                .setLarghezzaCm(sourceMtbColt.getLarghezzaCm())
                .setLunghezzaCm(sourceMtbColt.getLunghezzaCm())
                .setAltezzaCm(sourceMtbColt.getAltezzaCm())
                .setCodMdep(sourceMtbColt.getCodMdep())
                .setDataVers(UtilityDate.getDateInstance())
                .setOraFinePrep(UtilityDate.getDateInstance());

        newMtbColt.setOperation(CommonModelConsts.OPERATION.INSERT);


        if (posizione != null) {
            newMtbColt.setPosizione(posizione.getPosizione());
            if (posizione.isFlagLineaProduzione()) {
                newMtbColt.setCodJfas(posizione.getPosizione());
            }
        }


//        if (sourceMtbColt.getMtbColr().size() != 1) {
//            onFailed.run(new Exception());
//            return;
//        }
        MtbColr original = sourceMtbColr;
        MtbColr mtbColrClone = new MtbColr();
        mtbColrClone
                .setNumCollo(null)
                .setDataCollo((String) null)
                .setRiga(null)
                .setGestione(GestioneEnum.LAVORAZIONE)
                .setDataColloRif(sourceMtbColt.getDataColloD())
                .setNumColloRif(sourceMtbColt.getNumCollo())
                .setGestioneRif(sourceMtbColt.getGestione())
                .setSerColloRif(sourceMtbColt.getSerCollo())
                .setCodMart(original.getCodMart())
                .setCodCol(original.getCodCol())
                .setQtaCnf(original.getQtaCnf())
                .setCodTagl(original.getCodTagl())
                .setPartitaMag(original.getPartitaMag())
                .setOperation(CommonModelConsts.OPERATION.INSERT);
        for (OrdineLavorazioneDTO ordLav : ordini) {
            if (ordLav.getQtaColVersamento().getBigDecimal().compareTo(BigDecimal.ZERO) > 0) {
                MtbColr ordColr = (MtbColr) mtbColrClone.clone();
                ordColr.setQtaCol(ordLav.getQtaColVersamento().getBigDecimal());
                ordColr.setNumCnf(ordLav.getNumCnfVersamento().getBigDecimal());
                ordColr.setDataOrd(ordLav.getDataOrdProd())
                        .setNumOrd(ordLav.getNumOrdProd())
                        .setRigaOrd(ordLav.getRigaOrdProd());
                newMtbColt.getMtbColr().add(ordColr);
            }


        }

        saveCollo(newMtbColt, onComplete, onFailed);
    }

    public void createColloFromEtichettaAnonima(BarcodeScanDTO barcodeScanDTO, GestioneEnum gestione, RunnableArgs<MtbColt> onComplete, RunnableArgs<Exception> onFailed) {
        createColloFromEtichettaAnonima(barcodeScanDTO.getStringValue(), gestione, onComplete, onFailed);
    }

    public void createColloFromEtichettaAnonima(String barcode, GestioneEnum gestione, RunnableArgs<MtbColt> onComplete, RunnableArgs<Exception> onFailed) {

        MtbColt mtbColtToCreate = new MtbColt()
                .initDefaultFields(gestione);

        Integer customNumCollo = null;

        try {
            customNumCollo = UtilityBarcode.getNumColloFromULAnonima(barcode);
        } catch (Exception ex) {
            onFailed.run(ex);
        }

        String customSerCollo = CommonConst.Config.DEFAULT_ANONYMOUS_UL_SERIE;

        if (customNumCollo != null) {
            mtbColtToCreate.setNumCollo(customNumCollo);
        }

        if (!UtilityString.isNullOrEmpty(customSerCollo)) {
            mtbColtToCreate.setSerCollo(customSerCollo);
        }

        if (!UtilityBarcode.isEtichettaAnonimaOfCurrentYear(barcode)) {
            onFailed.run(new Exception("Per continuare scansiona un'etichetta dell'anno corrente"));
            return;
        }

        mtbColtToCreate
                .setOperation(CommonModelConsts.OPERATION.INSERT);

        saveCollo(mtbColtToCreate, onComplete, onFailed);
    }

    public void deleteCollo(MtbColt mtbColtToDelete, Runnable onComplete, RunnableArgs<Exception> onFailed) {

        mtbColtToDelete.setOperation(CommonModelConsts.OPERATION.DELETE);

        saveCollo(mtbColtToDelete, value -> {
            if (onComplete != null) onComplete.run();
        }, onFailed);
    }

    public static void distribuisciCollo(MtbColt mtbColtToDistribute, DistribuzioneColloDTO.CriterioDistribuzione criterioDistribuzione, RunnableArgs<List<MtbColt>> onComplete, RunnableArgs<Exception> onFailed) {

        DistribuzioneColloDTO distribuzioneColloDTO = new DistribuzioneColloDTO()
                .setCriterioDistribuzione(criterioDistribuzione)
                .setDataCollo(mtbColtToDistribute.getDataColloS())
                .setNumCollo(mtbColtToDistribute.getNumCollo())
                .setGestione(mtbColtToDistribute.getGestione())
                .setSerCollo(mtbColtToDistribute.getSerCollo());

        ColliMagazzinoRESTConsumerService colliMagazzinoRESTConsumerService = RESTBuilder.getService(ColliMagazzinoRESTConsumerService.class);
        colliMagazzinoRESTConsumerService.distribuisciCollo(distribuzioneColloDTO)
                .enqueue(new Callback<ServiceRESTResponse<JsonObject>>() {
                    @Override
                    public void onResponse(Call<ServiceRESTResponse<JsonObject>> call, Response<ServiceRESTResponse<JsonObject>> response) {
                        analyzeAnswerList(response, "DistribuzioneCollo", obj -> {

                            Gson gson = new Gson();
                            List<JsonObject> jsons = response.body().getEntityList();

                            List<MtbColt> newList = new ArrayList<>();

                            if (jsons != null) {
                                for (int i = 0; i < jsons.size(); i++) {
                                    JsonObject jsonTmp = jsons.get(i);

                                    newList.add(gson.fromJson(jsonTmp, MtbColt.class));
                                }
                            }

                            onComplete.run(newList);
                        }, onFailed);
                    }

                    @Override
                    public void onFailure(Call<ServiceRESTResponse<JsonObject>> call, Throwable t) {
                        onFailed.run(new Exception(t));
                    }
                });

    }

    public void getBySSCC(String ssccString, boolean onlyResiduo, boolean throwExcIfNull, RunnableArgs<MtbColt> onComplete, RunnableArgs<Exception> onFailed) {
        ColliMagazzinoRESTConsumerService colliMagazzinoRESTConsumerService = RESTBuilder.getService(ColliMagazzinoRESTConsumerService.class);
        colliMagazzinoRESTConsumerService.getColloByBarcode(ssccString, onlyResiduo, throwExcIfNull).enqueue(new Callback<>() {
            @Override
            public void onResponse(Call<ServiceRESTResponse<MtbColt>> call, Response<ServiceRESTResponse<MtbColt>> response) {
                analyzeAnswer(response, "GetBySSCC", mtbColt -> {

                    if (mtbColt != null && mtbColt.getMtbColr() != null && mtbColt.getMtbColr().size() > 0) {
                        List<MtbColt> mtbColtList = new ArrayList<>();
                        mtbColtList.add(mtbColt);
                        fillMtbAartsOfMtbColtsStatic(mtbColtList, mtbColts -> onComplete.run(mtbColts.get(0)), onFailed);
                    } else {
                        onComplete.run(mtbColt);
                    }

                }, onFailed);
            }

            @Override
            public void onFailure(Call<ServiceRESTResponse<MtbColt>> call, Throwable t) {
                onFailed.run(new Exception(t));
            }
        });
    }

    public void fillMtbAartsOfMtbColts(List<MtbColt> mtbColts, RunnableArgs<List<MtbColt>> onComplete, RunnableArgs<Exception> onFailed) {
        fillMtbAartsOfMtbColtsStatic(mtbColts, onComplete, onFailed);
    }

    public static void fillMtbAartsOfMtbColtsStatic(List<MtbColt> mtbColts, RunnableArgs<List<MtbColt>> onComplete, RunnableArgs<Exception> onFailed) {
        List<String> codMarts = new ArrayList<>();

        for (MtbColt mtbColt : mtbColts) {
            codMarts.addAll(Stream.of(mtbColt.getMtbColr())
                    .map(MtbColr::getCodMart)
                    .withoutNulls()
                    .distinct()
                    .toList());
        }


        ArticoloRESTConsumer.getByCodMartsStatic(codMarts, arts -> {

            if (arts != null && arts.size() > 0) {
                for (MtbColt mtbColt : mtbColts) {
                    for (MtbColr mtbColr : mtbColt.getMtbColr()) {

                        MtbAart foundMtbAart = null;

                        List<MtbAart> mtbAartStream = Stream.of(arts)
                                .filter(x -> x.getCodMart().equalsIgnoreCase(mtbColr.getCodMart())).toList();

                        if (mtbAartStream != null && mtbAartStream.size() > 0) {
                            foundMtbAart = mtbAartStream.get(0);
                        }

                        mtbColr.setMtbAart(foundMtbAart);
                        mtbColr.setGestione(mtbColt.getGestione());
                        mtbColr.setSerCollo(mtbColt.getSerCollo());
                        mtbColr.setNumCollo(mtbColt.getNumCollo());
                        mtbColr.setDataCollo(mtbColt.getDataColloS());
                    }
                }
            }

            onComplete.run(mtbColts);
        }, onFailed);
    }

    public void getMultipleByTestate(List<MtbColt> testate, boolean onlyResiduo, RunnableArgs<List<MtbColt>> onComplete, RunnableArgs<Exception> onFailed) {
        ArrayList<MtbColt> resultMtbColt = new ArrayList<>();
        cyclicGetMultipleByTestate(testate.iterator(), onlyResiduo, resultMtbColt, () -> {
            onComplete.run(resultMtbColt);
        }, onFailed);
    }

    private void cyclicGetMultipleByTestate(@NotNull Iterator<MtbColt> sourceMtbColts, boolean onlyResiduo, ArrayList<MtbColt> resultMtbColt, Runnable onComplete, RunnableArgs<Exception> onAbort) {
        if (sourceMtbColts.hasNext()) {
            getByTestata(sourceMtbColts.next(), onlyResiduo, false, mtbColt -> {
                resultMtbColt.add(mtbColt);
                cyclicGetMultipleByTestate(sourceMtbColts, onlyResiduo, resultMtbColt, onComplete, onAbort);
            }, onAbort);
        } else {
            onComplete.run();
        }
    }

    public void getByChiaveCollo(GestioneEnum gestione, int numCollo, String dataCollo, String serCollo, boolean onlyResiduo, boolean throwExcIfNull, RunnableArgs<MtbColt> onComplete, RunnableArgs<Exception> onFailed) {
        MtbColt mtbColtToRetrieve = new MtbColt()
                .setGestione(gestione)
                .setNumCollo(numCollo)
                .setDataCollo(dataCollo)
                .setSerCollo(serCollo);

        getByTestata(mtbColtToRetrieve, onlyResiduo, throwExcIfNull, onComplete, onFailed);
    }

    public void getByTestata(MtbColt testata, boolean onlyResiduo, boolean throwExcIfNull, RunnableArgs<MtbColt> onComplete, RunnableArgs<Exception> onFailed) {
        testata.setMtbColr(new ObservableArrayList<>());


        ColliMagazzinoRESTConsumerService colliMagazzinoRESTConsumerService = RESTBuilder.getService(ColliMagazzinoRESTConsumerService.class);
        colliMagazzinoRESTConsumerService.getColloInGiac(onlyResiduo, throwExcIfNull, testata).enqueue(new Callback<ServiceRESTResponse<MtbColt>>() {
            @Override
            public void onResponse(Call<ServiceRESTResponse<MtbColt>> call, Response<ServiceRESTResponse<MtbColt>> response) {
                analyzeAnswer(response, "getColloInGiac", mtbColt -> {

                    if (mtbColt != null && mtbColt.getMtbColr() != null && mtbColt.getMtbColr().size() > 0) {
                        List<MtbColt> mtbColtList = new ArrayList<>();
                        mtbColtList.add(mtbColt);
                        fillMtbAartsOfMtbColtsStatic(mtbColtList, mtbColts -> onComplete.run(mtbColts.get(0)), onFailed);
                    } else {
                        onComplete.run(mtbColt);
                    }

                }, onFailed);
            }

            @Override
            public void onFailure(Call<ServiceRESTResponse<MtbColt>> call, Throwable t) {
                onFailed.run(new Exception(t));
            }
        });
    }

    public void changePosizione(MtbColt mtbColtToMove, MtbDepoPosizione posizione, Runnable onComplete, RunnableArgs<Exception> onFailed) {

        String codMdep = posizione.getCodMdep();
        String posizioneString = posizione.getPosizione();

        MtbColt mtbColtToMoveClone = (MtbColt) mtbColtToMove.clone();

        for (int i = 0; i < mtbColtToMoveClone.getMtbColr().size(); i++) {
            mtbColtToMoveClone.getMtbColr().get(i)
                    .setMtbAart(null)
                    .setMtbPartitaMag(null);
        }

        ColliMagazzinoRESTConsumerService colliMagazzinoRESTConsumerService = RESTBuilder.getService(ColliMagazzinoRESTConsumerService.class);
        colliMagazzinoRESTConsumerService
                .spostaULInPosizione(codMdep,
                        posizioneString,
                        mtbColtToMoveClone)
                .enqueue(new Callback<ServiceRESTResponse<Object>>() {
                    @Override
                    public void onResponse(Call<ServiceRESTResponse<Object>> call, Response<ServiceRESTResponse<Object>> response) {
                        analyzeAnswer(response, "changePosizione", mtbColts -> {
                            onComplete.run();
                        }, onFailed);
                    }

                    @Override
                    public void onFailure(Call<ServiceRESTResponse<Object>> call, Throwable t) {
                        if (onFailed != null) onFailed.run(new Exception(t));
                    }
                });
    }

    public void updateDataFine(MtbColt mtbColt, Runnable onComplete, RunnableArgs<Exception> onFailed) {

        MtbColt cloneMtbColt = (MtbColt) mtbColt.clone();
        cloneMtbColt.setOperation(CommonModelConsts.OPERATION.UPDATE);
        cloneMtbColt.setOraFinePrep(UtilityDate.getDateInstance());
        cloneMtbColt.setMtbColr(new ObservableArrayList<>());

        saveCollo(cloneMtbColt, value -> {
            onComplete.run();
        }, ex -> {
            if (onFailed != null) onFailed.run(ex);
        });

    }

    public void canLUBeDeleted(MtbColt mtbColt, RunnableArgs<Boolean> onComplete, RunnableArgs<Exception> onFailed) {

        HashMap<String, Object> params = new HashMap<>();
        params.put("mtb_colt.gestione", mtbColt.getGestione());
        params.put("mtb_colt.ser_collo", mtbColt.getSerCollo());
        params.put("mtb_colt.num_collo", mtbColt.getNumCollo());
        params.put("mtb_colt.data_collo", mtbColt.getDataColloD());

        String whereCond = UtilityQuery.concatFieldsInWhereCond(params);


        String query = "SELECT mtb_colt.* " +
                "FROM mtb_colt " +
                "LEFT OUTER JOIN " +
                "  (SELECT gestione, " +
                "          data_collo, " +
                "          num_collo, " +
                "          ser_collo, " +
                "          cod_mart, " +
                "          cod_col, " +
                "          cod_tagl, " +
                "          partita_mag, " +
                "          SUM(qta_col) sum_qta_col " +
                "   FROM mtb_colr " +
                "   GROUP BY gestione, " +
                "            data_collo, " +
                "            num_collo, " +
                "            ser_collo, " +
                "            cod_mart, " +
                "            cod_col, " +
                "            cod_tagl, " +
                "            partita_mag) sum_mtb_colr ON mtb_colt.gestione = sum_mtb_colr.gestione " +
                "AND mtb_colt.num_collo = sum_mtb_colr.num_collo " +
                "AND mtb_colt.data_collo = sum_mtb_colr.data_collo " +
                "AND mtb_colt.ser_collo = sum_mtb_colr.ser_collo " +
                "AND sum_mtb_colr.sum_qta_col > 0 " +
                "WHERE sum_mtb_colr.num_collo IS NULL " +
                "  AND " + whereCond;


        Type typeOfObjectsList = new TypeToken<ArrayList<MtbColt>>() {
        }.getType();
        this.mSystemRESTConsumer.<ArrayList<MtbColt>>processSql(query, typeOfObjectsList, data -> {
            onComplete.run(data != null && data.size() > 0);
        }, onFailed);
    }

    public static void retrieveBasketColli(RunnableArgs<List<MtbColt>> onComplete, RunnableArgs<Exception> onFailed) {
        ColliMagazzinoRESTConsumerService colliMagazzinoRESTConsumerService = RESTBuilder.getService(ColliMagazzinoRESTConsumerService.class);
        colliMagazzinoRESTConsumerService.getColliInBasket(SettingsManager.i().getUserSession().getDepo().getCodMdep()).enqueue(new Callback<ServiceRESTResponse<List<MtbColt>>>() {
            @Override
            public void onResponse(Call<ServiceRESTResponse<List<MtbColt>>> call, Response<ServiceRESTResponse<List<MtbColt>>> response) {
                analyzeAnswer(response, "getColliInBasket", mtbColts -> {
                    fillMtbAartsOfMtbColtsStatic(mtbColts, onComplete, onFailed);
                }, onFailed);
            }

            @Override
            public void onFailure(Call<ServiceRESTResponse<List<MtbColt>>> call, Throwable t) {
                if (onFailed != null) onFailed.run(new Exception(t));
            }
        });
    }

    public void creaRettificaCollo(MtbColr sourceMtbColrOriginal, BigDecimal newNumCnf, BigDecimal newQtaTot, RunnableArgs<MtbColr> onComplete, RunnableArgs<Exception> onFailed) {
        MtbColr sourceMtbColr = (MtbColr) sourceMtbColrOriginal.clone();
        sourceMtbColr.setMtbPartitaMag(null);
        sourceMtbColr.setMtbAart(null);

        RettificaULDTO rettificaULDTO = new RettificaULDTO()
                .setSourceMtbColr(sourceMtbColr)
                .setNewNumCnf(newNumCnf)
                .setNewQtaCol(newQtaTot);

        ColliMagazzinoRESTConsumerService colliMagazzinoRESTConsumerService = RESTBuilder.getService(ColliMagazzinoRESTConsumerService.class);
        colliMagazzinoRESTConsumerService.creaRettificaCollo(
                SettingsManager.i().getUserSession().getDepo().getCodMdep(),
                rettificaULDTO
        ).enqueue(new Callback<>() {
            @Override
            public void onResponse(Call<ServiceRESTResponse<MtbColr>> call, Response<ServiceRESTResponse<MtbColr>> response) {
                analyzeAnswer(response, "creaRettificaCollo", onComplete, onFailed);
            }

            @Override
            public void onFailure(Call<ServiceRESTResponse<MtbColr>> call, Throwable t) {
                if (onFailed != null) onFailed.run(new Exception(t));
            }
        });
    }

    public void spostaArtsTraUL(MtbColt sourceMtbColt, MtbColt destMtbColt, Runnable onComplete, RunnableArgs<Exception> onFailed) {
        new Thread(() -> {
            MtbColt mtbColtToMoveClone = (MtbColt) sourceMtbColt.clone();
            MtbColt mtbColtDestClone = (MtbColt) destMtbColt.clone();

            for (int i = 0; i < mtbColtToMoveClone.getMtbColr().size(); i++) {
                mtbColtToMoveClone.getMtbColr().get(i)
                        .setMtbAart(null)
                        .setMtbPartitaMag(null);
            }

            mtbColtDestClone.setMtbColr(null);

            SpostaArtsTraULRequestDTO spostaArtsTraULRequestDTO = new SpostaArtsTraULRequestDTO()
                    .setSourceMtbColt(mtbColtToMoveClone)
                    .setDestinationMtbColt(mtbColtDestClone);

            ColliMagazzinoRESTConsumerService colliMagazzinoRESTConsumerService = RESTBuilder.getService(ColliMagazzinoRESTConsumerService.class);
            colliMagazzinoRESTConsumerService.spostaArtsTraUL(spostaArtsTraULRequestDTO).enqueue(new Callback<>() {
                @Override
                public void onResponse(Call<ServiceRESTResponse<Object>> call, Response<ServiceRESTResponse<Object>> response) {
                    analyzeAnswer(response, "spostaArtsTraUL", data -> {
                        onComplete.run();
                    }, onFailed);
                }

                @Override
                public void onFailure(Call<ServiceRESTResponse<Object>> call, Throwable t) {
                    if (onFailed != null) onFailed.run(new Exception(t));
                }
            });
        }).start();
    }

    public void assegnaLottoSuColloScarico(MtbColt sourceMtbColt, Runnable onComplete, RunnableArgs<Exception> onFailed) {
        MtbColt sourceMtbColtClone = (MtbColt) sourceMtbColt.clone();

        for (int i = 0; i < sourceMtbColtClone.getMtbColr().size(); i++) {
            sourceMtbColtClone.getMtbColr().get(i)
                    .setMtbAart(null)
                    .setMtbPartitaMag(null);
        }

        ColliMagazzinoRESTConsumerService colliMagazzinoRESTConsumerService = RESTBuilder.getService(ColliMagazzinoRESTConsumerService.class);
        colliMagazzinoRESTConsumerService.assegnaLottoSuColloScarico(sourceMtbColtClone).enqueue(new Callback<>() {
            @Override
            public void onResponse(Call<ServiceRESTResponse<MtbColt>> call, Response<ServiceRESTResponse<MtbColt>> response) {
                analyzeAnswer(response, "assegnaLottoSuColloScarico", data -> {
                    onComplete.run();
                }, onFailed);
            }

            @Override
            public void onFailure(Call<ServiceRESTResponse<MtbColt>> call, Throwable t) {
                if (onFailed != null) onFailed.run(new Exception(t));
            }
        });
    }

    public void versamentoAutomaticoUL(MtbColt sourceMtbColt, RunnableArgs<VersamentoAutomaticoULResponseDTO> onComplete, RunnableArgs<Exception> onFailed) {
        MtbColt sourceMtbColtClone = (MtbColt) sourceMtbColt.clone();

        for (int i = 0; i < sourceMtbColtClone.getMtbColr().size(); i++) {
            sourceMtbColtClone.getMtbColr().get(i)
                    .setMtbAart(null)
                    .setMtbPartitaMag(null);
        }

        ColliMagazzinoRESTConsumerService colliMagazzinoRESTConsumerService = RESTBuilder.getService(ColliMagazzinoRESTConsumerService.class);
        colliMagazzinoRESTConsumerService.versamentoAutomaticoUL(sourceMtbColtClone).enqueue(new Callback<>() {
            @Override
            public void onResponse(Call<ServiceRESTResponse<VersamentoAutomaticoULResponseDTO>> call, Response<ServiceRESTResponse<VersamentoAutomaticoULResponseDTO>> response) {
                analyzeAnswer(response, "versamentoAutomaticoUL", data -> {
                    var result = response.body().getDto();

                    List<MtbColr> allMtbColr = new ArrayList<>();
                    allMtbColr.addAll(result.getSuccess());
                    allMtbColr.addAll(result.getFailed());

                    List<String> codMarts = Stream.of(allMtbColr)
                            .map(x -> x.getCodMart().trim())
                            .toList();

                    mArticoloRESTConsumer.getByCodMarts(codMarts, mtbAarts -> {
                        for (var mtbColr : allMtbColr) {

                            MtbAart foundMtbAart = null;

                            Optional<MtbAart> mtbAartOpt = Stream.of(mtbAarts)
                                    .filter(x -> x.getCodMart().equalsIgnoreCase(mtbColr.getCodMart()))
                                    .findFirst();

                            if (mtbAartOpt.isPresent()) {
                                foundMtbAart = mtbAartOpt.get();
                            }

                            mtbColr.setMtbAart(foundMtbAart);
                        }

                        onComplete.run(result);
                    }, onFailed);

                }, onFailed);
            }

            @Override
            public void onFailure(Call<ServiceRESTResponse<VersamentoAutomaticoULResponseDTO>> call, Throwable t) {
                if (onFailed != null) onFailed.run(new Exception(t));
            }
        });
    }

    public void loadShipmentUlFromProductionUL(MtbColt mtbColt, RunnableArgs<MtbColt> onComplete, RunnableArgs<Exception> onFailed) {

        HashMap<String, Object> params = new HashMap<>();
        params.put("mtb_colr.gestione_rif", mtbColt.getGestione());
        params.put("mtb_colr.ser_collo_rif", mtbColt.getSerCollo());
        params.put("mtb_colr.num_collo_rif", mtbColt.getNumCollo());
        params.put("mtb_colr.data_collo_rif", mtbColt.getDataColloD());

        String whereCond = UtilityQuery.concatFieldsInWhereCond(params);


        String query = "select distinct mtb_colt.*\n" +
                "from mtb_colt\n" +
                "         left join mtb_colr on mtb_colt.gestione = mtb_colr.gestione and mtb_colt.data_collo = mtb_colr.data_collo and\n" +
                "                               mtb_colt.ser_collo = mtb_colr.ser_collo and mtb_colt.num_collo = mtb_colr.num_collo\n" +
                "where mtb_colt.gestione = 'V'" +
                "  AND " + whereCond;


        Type typeOfObjectsList = new TypeToken<ArrayList<MtbColt>>() {
        }.getType();
        this.mSystemRESTConsumer.<ArrayList<MtbColt>>processSql(query, typeOfObjectsList, data -> {
            onComplete.run(data.get(0));
        }, onFailed);
    }
}
