package it.integry.integrywmsnative.core.data_store.db.repository.implementations;

import com.annimon.stream.Stream;

import org.apache.commons.lang3.StringUtils;

import java.util.ArrayList;
import java.util.List;

import javax.inject.Inject;

import it.integry.integrywmsnative.core.data_store.db.dao.ArticoloOrdineDao;
import it.integry.integrywmsnative.core.data_store.db.entity.ArticoloOrdine;
import it.integry.integrywmsnative.core.data_store.db.entity.Ordine;
import it.integry.integrywmsnative.core.data_store.db.repository.ArticoliOrdineRepository;
import it.integry.integrywmsnative.core.data_store.db.wrappers.ArticoloOrdineWrapper;
import it.integry.integrywmsnative.core.expansion.RunnableArgs;

public class ArticoliOrdineDataSource extends Repository implements ArticoliOrdineRepository {

    private final ArticoloOrdineDao mArticoloOrdineDao;

    @Inject
    public ArticoliOrdineDataSource(ArticoloOrdineDao articoloOrdineDao) {
        this.mArticoloOrdineDao = articoloOrdineDao;
    }

    public void saveArticoliToOrdine(List<ArticoloOrdine> articoli, Runnable onSuccess, RunnableArgs<Exception> onFail) {
        execute(() -> {
            try {
                List<ArticoloOrdine> toUpdate = new ArrayList<>();
                List<ArticoloOrdine> toInsert = new ArrayList<>();
                for (ArticoloOrdine art : articoli) {
                    if (art.getArticoloOrdineId() != null && art.getArticoloOrdineId() > 0) {
                        toUpdate.add(art);
                    } else {
                        toInsert.add(art);
                    }
                }
                for (ArticoloOrdine newArt : toInsert) {
                    mArticoloOrdineDao.insert(newArt);
                }
                mArticoloOrdineDao.updateAll(toUpdate);
                onSuccess.run();


            } catch (Exception e) {
                onFail.run(e);
            }
        });
    }

    public void saveArticoloToOrdine(ArticoloOrdine articolo, Runnable onSuccess, RunnableArgs<Exception> onFail) {
        execute(() -> {
            try {
                if (articolo.getArticoloOrdineId() != null && articolo.getArticoloOrdineId() > 0) {
                    mArticoloOrdineDao.update(articolo);
                } else {
                    mArticoloOrdineDao.insert(articolo);
                }
                onSuccess.run();
            } catch (Exception e) {
                onFail.run(e);
            }
        });
    }

    public void findArticoloByOrdineAndBarcode(Ordine ordine, String barcode, RunnableArgs<ArticoloOrdine> onSuccess, RunnableArgs<Exception> onFail) {
        execute(() -> {
            try {
                ArticoloOrdine articolo = mArticoloOrdineDao.findArticoloByOrdineAndBarcode(ordine.getOrdineId(), barcode);
                onSuccess.run(articolo);
            } catch (Exception e) {
                onFail.run(e);
            }
        });
    }

    public void findArticoloByScanAndOrdine(Ordine ordine, String barcode, RunnableArgs<ArticoloOrdine> onSuccess, RunnableArgs<Exception> onFail) {
        execute(() -> {
            try {
                String scannedCode = barcode;
                ArticoloOrdine articolo = mArticoloOrdineDao.findArticoloByCodMartAndOrdine(ordine.getOrdineId(), scannedCode);
                if (articolo == null) {
                    articolo = mArticoloOrdineDao.findArticoloByBarcodeAndOrdine(ordine.getOrdineId(), scannedCode);
                    if (articolo == null) {
                        scannedCode = StringUtils.leftPad(scannedCode, 13, '0');
                        articolo = mArticoloOrdineDao.findArticoloByBarcodeAndOrdine(ordine.getOrdineId(), scannedCode);
                    }
                }
                onSuccess.run(articolo);
            } catch (Exception e) {
                onFail.run(e);
            }
        });
    }

    public void findArticoliByOrdine(Ordine ordine, RunnableArgs<List<ArticoloOrdine>> onLoad, RunnableArgs<Exception> onError) {
        execute(() -> {
            try {
                List<ArticoloOrdineWrapper> list = mArticoloOrdineDao.findArticoliByOrdine(ordine.getOrdineId());
                onLoad.run(Stream.of(list).map(x -> {
                    ArticoloOrdine art = x.getArticoloOrdine();
                    art.setGgScadenza(x.getGgScadenza());
                    art.setGiacenza(x.getGiacenza());
                    art.setQtaProposta(x.getQtaProposta());
                    art.setQtaPrevistaVendita(x.getQtaPrevistaVendita());
                    return art;
                }).toList());
            } catch (Exception e) {
                onError.run(e);
            }
        });
    }

    public void deleteArticolo(ArticoloOrdine articolo, Runnable onSave, RunnableArgs<Exception> onError) {
        execute(() -> {
            try {
                mArticoloOrdineDao.delete(articolo);
                onSave.run();
            } catch (Exception e) {
                onError.run(e);
            }
        });
    }

}
