package org.gcube.application.cms.plugins.reports;

import com.fasterxml.jackson.core.JsonProcessingException;
import lombok.Data;
import lombok.NonNull;
import lombok.extern.slf4j.Slf4j;
import org.bson.Document;
import org.gcube.application.cms.plugins.faults.InvalidPluginRequestException;
import org.gcube.application.cms.plugins.faults.PluginExecutionException;
import org.gcube.application.cms.plugins.requests.BaseExecutionRequest;
import org.gcube.application.geoportal.common.model.document.Project;
import org.gcube.application.geoportal.common.model.document.identification.IdentificationReference;
import org.gcube.application.geoportal.common.model.document.lifecycle.LifecycleInformation;

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


@Data

@Slf4j
public class DocumentHandlingReport<T extends BaseExecutionRequest> extends Report{

    @NonNull
    T theRequest;
    Document resultingDocument;
    LifecycleInformation toSetLifecycleInformation;

    protected List<IdentificationReference> toSetIdentificationReferences=null;

    public DocumentHandlingReport<T> addIdentificationReference(IdentificationReference toAdd){
        if(toSetIdentificationReferences == null) toSetIdentificationReferences = new ArrayList<>();
        toSetIdentificationReferences.add(toAdd);
        return this;
    }


    public DocumentHandlingReport(@NonNull T theRequest) throws InvalidPluginRequestException {
        theRequest.validate();
        this.theRequest = theRequest;
        this.setStatus(Status.OK);
        toSetLifecycleInformation=theRequest.getDocument().getLifecycleInformation();
        resultingDocument = theRequest.getDocument().getTheDocument();
    }

    @Override
    public void validate() throws PluginExecutionException {
        super.validate();
        if (resultingDocument==null) {
            log.warn("NULL resulting document in report {} ", this);
            throw new PluginExecutionException("Invalid report : Resulting document cannot be null");
        }
        if(toSetLifecycleInformation == null) {
            log.warn("NULL lifecycleinformation in report {} ",this);
            throw new PluginExecutionException("Invalid report : Lifecycle information cannot be null");
        }
    }

    public Project prepareResult() throws JsonProcessingException, PluginExecutionException {
        log.trace("Preparing document ID {} from report ... ",theRequest.getDocument().getId());
        this.validate();

        Project toReturn = theRequest.getDocument();
        toReturn.setTheDocument(resultingDocument);
        toReturn.setLifecycleInformation(toSetLifecycleInformation);

        // Force Report status into info
        log.trace("Report status is {} ",getStatus());
        LifecycleInformation info = toReturn.getLifecycleInformation();
        switch (getStatus()){
            case ERROR: {
                info.setLastOperationStatus(LifecycleInformation.Status.ERROR);
                this.getMessages().forEach(s -> info.addErrorMessage(s));
                break;
            }
            case WARNING:{
                info.setLastOperationStatus(LifecycleInformation.Status.WARNING);
                this.getMessages().forEach(s -> info.addWarningMessage(s));
                break;
            }
            case OK: {
                if(info.getLastOperationStatus()==null)
                    info.setLastOperationStatus(LifecycleInformation.Status.OK);
                break;
            }
        }
        if(toSetIdentificationReferences!=null)
            toReturn.setIdentificationReferences(toSetIdentificationReferences);
        return toReturn;
    }
}
