package it.integry.integrywmsnative.gest.contab_doc_interni;

import androidx.lifecycle.LiveData;
import androidx.lifecycle.MutableLiveData;

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

import javax.inject.Inject;

import it.integry.integrywmsnative.core.data_store.db.entity.SqlMtbColt;
import it.integry.integrywmsnative.core.data_store.db.repository.MtbColtRepository;
import it.integry.integrywmsnative.core.data_store.db.wrappers.DocInternoWrapper;
import it.integry.integrywmsnative.core.di.BindableInteger;
import it.integry.integrywmsnative.core.exception.NoDocTypeSelectedException;
import it.integry.integrywmsnative.core.interfaces.viewmodel_listeners.ILoadingListener;
import it.integry.integrywmsnative.core.rest.consumers.DocumentRESTConsumer;
import it.integry.integrywmsnative.core.rest.model.documento.DocumentoArtDTO;
import it.integry.integrywmsnative.core.settings.SettingsManager;
import it.integry.integrywmsnative.gest.contab_doc_interni.dialog.DialogSelectDocInfoResponseDTO;
import it.integry.integrywmsnative.gest.contab_doc_interni.dto.DocInterniSetupDTO;
import it.integry.integrywmsnative.gest.contab_doc_interni.dto.FornitoreDTO;
import it.integry.integrywmsnative.gest.contab_doc_interni.dto.GruppoArticoloDTO;
import it.integry.integrywmsnative.gest.contab_doc_interni.dto.TipoDocDTO;
import it.integry.integrywmsnative.gest.contab_doc_interni.rest.DocInterniRESTConsumer;

public class DocInterniViewModel {

    private final MtbColtRepository documentRepository;
    private final DocInterniRESTConsumer docInterniRESTConsumer;
    private final DocumentRESTConsumer documentRESTConsumer;

    private Listener mListener;
    private boolean productsFetched = true;
    private boolean docsFetched = true;
    private int nextNumCollo = 0;
    private List<DocumentoArtDTO> availableArts;
    private final MutableLiveData<List<DocInternoWrapper>> mDocsList = new MutableLiveData<>();

    public TipoDocDTO dtbTipi;
    public GruppoArticoloDTO mtbGrup;
    public FornitoreDTO fornitore;
    public Date dataDoc;
    public String numDoc;
    public String note;
    public final BindableInteger artsSize = new BindableInteger(0);

    @Inject
    public DocInterniViewModel(DocInterniRESTConsumer docInterniRESTConsumer,
                               MtbColtRepository documentRepository,
                               DocumentRESTConsumer documentRESTConsumer) {
        this.docInterniRESTConsumer = docInterniRESTConsumer;
        this.documentRepository = documentRepository;
        this.documentRESTConsumer = documentRESTConsumer;
    }


    public void init() {
        this.sendOnLoadingStarted();

        docInterniRESTConsumer.getDocInterniSetup(returnDto -> {
            this.sendOnLoadingEnded();
            this.mListener.onDocInterniSetupFetched(returnDto);
        }, this::sendError);
    }

    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 DocInterniViewModel setListeners(Listener listener) {
        this.mListener = listener;
        return this;
    }

    public LiveData<List<DocInternoWrapper>> getDocsList() {
        return mDocsList;
    }

    public void setSelectedDocDetails(DialogSelectDocInfoResponseDTO selection) {
        this.fornitore = selection.getFornitore();
        this.dtbTipi = selection.getTipoDoc();

        this.mtbGrup = selection.getGruppoArt();
        this.dataDoc = selection.getDataDoc();
        this.numDoc = selection.getNumDoc() != null ? selection.getNumDoc().toString() : null;
        this.note = selection.getNote();

        this.sendOnLoadingStarted();
        fetchProducts(() -> {
            fetchDocuments(this::sendOnLoadingEnded);
        });
    }

    public void fetchProducts(Runnable onComplete) {
        documentRESTConsumer.loadDocumentAvailableArts(
                this.getCodDtip(),
                this.getCodMgrp(),
                this.getCodAnagForn(),
                data -> {
                    this.productsFetched = true;
                    this.availableArts = data.getArts();
                    this.artsSize.set(this.availableArts.size());

                    onComplete.run();
                }, this::sendError);
    }

    public void fetchDocuments(Runnable onComplete) {
        String codAnag = null;
        String codVdes = null;

        FornitoreDTO fornitore = this.fornitore;
        if (fornitore != null) {
            codAnag = fornitore.getCodAnag();
            codVdes = fornitore.getCodVdes();
        }


        var docsList = documentRepository.getDocuments(this.getCodDtip(),
                codAnag, codVdes, dataDoc, numDoc);

        docsList.observeForever(data -> {
            this.mDocsList.postValue(data);
        });

        documentRepository.getNextNumCollo(nextNumCollo -> {
            this.setNextNumCollo(nextNumCollo);
            this.docsFetched = true;

            onComplete.run();
        }, this::sendError);
    }

    private void setNextNumCollo(Integer nextNumCollo) {
        this.nextNumCollo = nextNumCollo;
    }

    private String getCodDtip() {
        if (this.dtbTipi == null) {
            return null;
        }
        return this.dtbTipi.getCodDtip();
    }

    public TipoDocDTO getTipoDoc() {
        return this.dtbTipi;
    }

    private String getCodMgrp() {
        if (this.mtbGrup == null) {
            return null;
        }
        return this.mtbGrup.getCodMgrp();
    }

    private String getCodAnagForn() {
        if (this.fornitore == null) {
            return null;
        }
        return this.fornitore.getCodAnag();
    }

    public void editDocument(SqlMtbColt document) {
        this.mListener.onDocumentEditRequest(document, availableArts);
    }

    public void newDocument() {
        SqlMtbColt document = new SqlMtbColt();
        if (this.dtbTipi == null) {
            this.sendError(new NoDocTypeSelectedException());
            return;
        }
        document.setCodDtipProvv(this.getCodDtip());
        document.setCodMgrp(this.getCodMgrp());
        document.setDataCollo(new Date());
        document.setCodMdep(SettingsManager.i().getUserSession().getDepo().getCodMdep());
        document.setAnnotazioni(this.note);
        document.setSegno(-1);
        document.setSerCollo("/");
        document.setNumCollo(this.nextNumCollo);
        document.setGestione("L");
        document.setDataDoc(this.dataDoc);
        if (this.numDoc != null) {
            document.setNumDoc(Integer.parseInt(this.numDoc));
        }
        if (this.fornitore != null) {
            document.setCodAnag(this.fornitore.getCodAnag());
            document.setCodVdes(this.fornitore.getCodVdes());
        }
        documentRepository.insert(document, id -> {
            document.setId(id);
            this.editDocument(document);
        }, this::sendError);
    }

    public boolean hasDocDetails() {
        return this.dtbTipi != null;
    }

    public interface Listener extends ILoadingListener {

        void onError(Exception ex);

        void onDocInterniSetupFetched(DocInterniSetupDTO docInterniSetupDTO);

        void onDocDetailsChanged(DialogSelectDocInfoResponseDTO selection);

        void onDocumentEditRequest(SqlMtbColt document, List<DocumentoArtDTO> arts);

    }

}
