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

import com.annimon.stream.Optional;
import com.annimon.stream.Stream;
import com.google.gson.reflect.TypeToken;
import com.orhanobut.logger.Logger;

import java.lang.reflect.Type;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Random;

import javax.inject.Singleton;

import it.integry.integrywmsnative.core.expansion.RunnableArgs;
import it.integry.integrywmsnative.core.model.CommonModelConsts;
import it.integry.integrywmsnative.core.model.MtbColr;
import it.integry.integrywmsnative.core.model.MtbColt;
import it.integry.integrywmsnative.core.model.MtbPartitaMag;
import it.integry.integrywmsnative.core.model.OrdineInevasoDTO;
import it.integry.integrywmsnative.core.model.secondary.GestioneEnum;
import it.integry.integrywmsnative.core.rest.RESTBuilder;
import it.integry.integrywmsnative.core.rest.model.GetPickingListDTO;
import it.integry.integrywmsnative.core.rest.model.OrdineUscitaInevasoDTO;
import it.integry.integrywmsnative.core.rest.model.ServiceRESTResponse;
import it.integry.integrywmsnative.core.rest.model.SitArtOrdDTO;
import it.integry.integrywmsnative.core.utility.UtilityDB;
import it.integry.integrywmsnative.core.utility.UtilityLogger;
import it.integry.integrywmsnative.core.utility.UtilityQuery;
import it.integry.integrywmsnative.core.utility.UtilityString;
import it.integry.integrywmsnative.gest.spedizione.model.PickingObjectDTO;
import retrofit2.Call;
import retrofit2.Callback;
import retrofit2.Response;

@Singleton
public class OrdiniRESTConsumer extends _BaseRESTConsumer {

    private final SystemRESTConsumer mSystemRESTConsumer;
    private final EntityRESTConsumer mEntityRESTConsumer;

    public OrdiniRESTConsumer(SystemRESTConsumer systemRESTConsumer, EntityRESTConsumer entityRESTConsumer) {
        this.mSystemRESTConsumer = systemRESTConsumer;
        this.mEntityRESTConsumer = entityRESTConsumer;
    }

    public void getSuggestedPickingList(String codMdep, List<SitArtOrdDTO> sitArtOrdList, RunnableArgs<List<PickingObjectDTO>> onComplete, RunnableArgs<Exception> onFailed) {
        OrdiniRESTConsumerService service = RESTBuilder.getService(OrdiniRESTConsumerService.class, 90);
        service
                .getSuggestedPickingList(codMdep, sitArtOrdList)
                .enqueue(new Callback<>() {
                    @Override
                    public void onResponse(Call<ServiceRESTResponse<List<PickingObjectDTO>>> call, Response<ServiceRESTResponse<List<PickingObjectDTO>>> response) {
                        analyzeAnswer(response, "getSuggestedPickingList", pickingObjects -> {
                            List<MtbPartitaMag> batchLotsToSearch = new ArrayList<>();

                            for (PickingObjectDTO pickingObjectDTO : pickingObjects) {
                                for (MtbColt mtbColt : pickingObjectDTO.getMtbColts()) {
                                    Stream.of(mtbColt.getMtbColr())
                                            .filter(x -> !UtilityString.isNullOrEmpty(x.getPartitaMag()))
                                            .forEach(x -> {

                                                if (!Stream.of(batchLotsToSearch)
                                                        .anyMatch(batchLotToSearch ->
                                                                batchLotToSearch.getCodMart().equalsIgnoreCase(x.getCodMart()) &&
                                                                batchLotToSearch.getPartitaMag().equalsIgnoreCase(x.getPartitaMag()))) {
                                                    MtbPartitaMag mtbPartitaMag = new MtbPartitaMag()
                                                            .setCodMart(x.getCodMart())
                                                            .setPartitaMag(x.getPartitaMag());

                                                    mtbPartitaMag.setOperation(CommonModelConsts.OPERATION.SELECT_OBJECT);
                                                    mtbPartitaMag.setOnlyPkMaster(false);

                                                    batchLotsToSearch.add(mtbPartitaMag);
                                                }
                                            });
                                }
                            }

                            Random rand = new Random();


                            retrievePartiteMag(batchLotsToSearch, partite -> {

                                for (PickingObjectDTO pickingObjectDTO : pickingObjects) {
                                    for (MtbColt mtbColt : pickingObjectDTO.getMtbColts()) {
                                        for (MtbColr mtbColr : mtbColt.getMtbColr()) {

                                            mtbColr.setId(rand.nextInt());

                                            Optional<MtbPartitaMag> optionalMtbPartitaMag = Stream.of(partite)
                                                    .filter(x -> x.getCodMart().equalsIgnoreCase(mtbColr.getCodMart())
                                                            && (!UtilityString.isNullOrEmpty(x.getPartitaMag()) && x.getPartitaMag().equalsIgnoreCase(mtbColr.getPartitaMag())))
                                                    .findFirst();

                                            if (optionalMtbPartitaMag.isPresent())
                                                mtbColr.setMtbPartitaMag(optionalMtbPartitaMag.get());
                                        }
                                    }
                                }

                                onComplete.run(pickingObjects);

                            }, onFailed);


                        }, onFailed);
                    }

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

    }

    private void retrievePartiteMag(List<MtbPartitaMag> partitaMag, RunnableArgs<List<MtbPartitaMag>> onComplete, RunnableArgs<Exception> onFailed) {

        this.mEntityRESTConsumer.processEntityList(partitaMag, true, MtbPartitaMag.class, onComplete, onFailed);
    }

    public void getOrdiniInevasi(String codMdep, GestioneEnum gestione, RunnableArgs<List<OrdineUscitaInevasoDTO>> onComplete, RunnableArgs<Exception> onFailed) {

        OrdiniRESTConsumerService service = RESTBuilder.getService(OrdiniRESTConsumerService.class);

        service.getOrdiniInevasi(codMdep, gestione.getText())
                .enqueue(new Callback<>() {
                    @Override
                    public void onResponse(Call<ServiceRESTResponse<List<OrdineUscitaInevasoDTO>>> call, Response<ServiceRESTResponse<List<OrdineUscitaInevasoDTO>>> response) {
                        analyzeAnswer(response, "getOrdiniInevasi", responseDtoList -> {
                            if (responseDtoList == null) responseDtoList = new ArrayList<>();
                            onComplete.run(responseDtoList);
                        }, ex -> {
                            Logger.e(ex, "Errore durante il caricamento degli ordini di lavorazione");
                            if (onFailed != null) onFailed.run(ex);
                        });
                    }

                    @Override
                    public void onFailure(Call<ServiceRESTResponse<List<OrdineUscitaInevasoDTO>>> call, Throwable t) {
                        Logger.e(t, "Errore durante il caricamento degli ordini di lavorazione");
                        if (onFailed != null) onFailed.run(new Exception(t));
                    }
                });
    }

    public void retrieveListaArticoliFromOrdiniUscita(String codMdep, List<OrdineUscitaInevasoDTO> orders, RunnableArgs<List<SitArtOrdDTO>> onComplete, RunnableArgs<Exception> onFailed) {
        List<GetPickingListDTO> getPickingListDTOs = Stream.of(orders)
                .map(x -> new GetPickingListDTO()
                        .setData(x.getDataOrdS())
                        .setGestione(x.getGestione())
                        .setNumero(x.getNumOrd())
                        .setDataConsegna(x.getDataConsS())
                        .setIdViaggio(x.getIdViaggio()))
                .toList();

        OrdiniRESTConsumerService service = RESTBuilder.getService(OrdiniRESTConsumerService.class, 90);

        service.getArticoliFromOrdini(codMdep, getPickingListDTOs).enqueue(new Callback<>() {
            @Override
            public void onResponse(Call<ServiceRESTResponse<List<SitArtOrdDTO>>> call, Response<ServiceRESTResponse<List<SitArtOrdDTO>>> response) {
                analyzeAnswer(response, "retrieveListaArticoliFromOrdiniUscita", sitArtOrds -> {
                    if (sitArtOrds != null) {
                        for (SitArtOrdDTO sitArtOrd : sitArtOrds) {
                            sitArtOrd.setCodMart(sitArtOrd.getCodMart().trim());
                        }
                    }

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

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


    public void getBancaliGiaRegistrati(List<OrdineInevasoDTO> orders, GestioneEnum gestione, int segno, RunnableArgs<List<MtbColt>> onComplete, RunnableArgs<Exception> onFailed) {
        String whereCondGestione = "";

        if (gestione != null) {
            whereCondGestione = "mtb_colt.gestione = " + UtilityDB.valueToString(gestione.getText()) + " ";
        } else {
            whereCondGestione = "(mtb_colt.gestione = 'V' OR mtb_colt.gestione = 'L') ";
        }

        String baseSql = "SELECT DISTINCT mtb_colt.* " +
                "FROM mtb_colt " +
                "       INNER JOIN mtb_colr ON " +
                "       mtb_colt.gestione = mtb_colr.gestione " +
                "        AND mtb_colt.ser_collo = mtb_colr.ser_collo " +
                "        AND mtb_colt.data_collo = mtb_colr.data_collo " +
                "        AND mtb_colt.num_collo = mtb_colr.num_collo " +
                " WHERE " + whereCondGestione +
                "  AND mtb_colt.segno = " + UtilityDB.valueToString(segno) + " " +
                "  AND mtb_colt.data_doc IS NULL AND ";

        List<HashMap<String, Object>> whereCondMapList = new ArrayList<>();
        for (OrdineInevasoDTO ordineInevaso : orders) {
            HashMap<String, Object> whereCondMap = new HashMap<>();
            whereCondMap.put("mtb_colr.data_ord", ordineInevaso.getDataOrdD());
            whereCondMap.put("mtb_colr.num_ord", ordineInevaso.getNumOrd());
            whereCondMap.put("mtb_colr.gestione", ordineInevaso.getGestione());

            whereCondMapList.add(whereCondMap);
        }

        baseSql += "(" + UtilityQuery.concatFieldListInWhereCond(whereCondMapList) + ")";

        Type typeOfObjectsList = new TypeToken<ArrayList<MtbColt>>() {
        }.getType();
        this.mSystemRESTConsumer.<List<MtbColt>>processSql(baseSql, typeOfObjectsList, value -> {
            if (onComplete != null) onComplete.run(value);
        }, ex -> {
            if (onFailed != null) onFailed.run(ex);
        });
    }

}
