package be.iminds.ilabt.jfed.highlevel.tasks;

import be.iminds.ilabt.jfed.highlevel.controller.JFedHighLevelException;
import be.iminds.ilabt.jfed.highlevel.controller.Task;
import be.iminds.ilabt.jfed.highlevel.controller.TaskExecution;
import be.iminds.ilabt.jfed.highlevel.model.Slice;
import be.iminds.ilabt.jfed.lowlevel.GeniUserProvider;
import be.iminds.ilabt.jfed.lowlevel.JFedException;
import be.iminds.ilabt.jfed.lowlevel.api.StitchingComputationService;
import be.iminds.ilabt.jfed.fedmon.webapi.service.json.*;
import be.iminds.ilabt.jfed.lowlevel.connection.JFedConnectionProvider;
import be.iminds.ilabt.jfed.lowlevel.connection.SfaConnection;
import be.iminds.ilabt.jfed.preferences.JFedPreferences;
import be.iminds.ilabt.jfed.rspec.model.ModelRspec;
import be.iminds.ilabt.jfed.rspec.rspec_source.RequestRspecSource;
import be.iminds.ilabt.jfed.util.JavaFXLogger;
import org.slf4j.LoggerFactory;

import javax.annotation.Nonnull;
import java.time.Instant;
import java.util.Date;

/**
 * User: twalcari
 * Date: 12/3/2015
 * Time: 14:58
 */
public class SCSRequestTask extends Task {
    private static final org.slf4j.Logger log = LoggerFactory.getLogger(SCSRequestTask.class);

    @Nonnull
    private final Server scsAuthority;
    @Nonnull
    private final Slice slice;
    @Nonnull
    private final RequestRspecSource originalRspecRequest;
    @Nonnull
    private final Instant requestedEndTime;
    private final GeniUserProvider geniUserProvider;
    private final JavaFXLogger logger;
    private final JFedConnectionProvider connectionProvider;
    private final JFedPreferences jFedPreferences;

    private StitchingComputationService.ComputePathResult result;

    public SCSRequestTask(@Nonnull Slice slice, @Nonnull RequestRspecSource requestRspecSource, @Nonnull Instant requestedEndTime,
                          @Nonnull Server scsAuthority,
                          GeniUserProvider geniUserProvider, JavaFXLogger logger,
                          JFedConnectionProvider connectionProvider, JFedPreferences jFedPreferences) {
        super("ParallelStitcher StitchingComputationService call");
        this.slice = slice;
        this.originalRspecRequest = requestRspecSource;
        this.requestedEndTime = requestedEndTime;
        this.geniUserProvider = geniUserProvider;
        this.logger = logger;
        this.connectionProvider = connectionProvider;
        this.jFedPreferences = jFedPreferences;

        this.scsAuthority = scsAuthority;
    }

    @Override
    protected void doTask(TaskExecution taskExecution) throws JFedException, InterruptedException {
        log.debug("Sending StitchingComputationService request");
        StitchingComputationService scs =
                new StitchingComputationService(JavaFXLogger.wrap(logger, taskExecution), jFedPreferences);

        assert geniUserProvider.isUserLoggedIn();

        //see FEDIBBTDEV-1334: ION and others see "expires" in the request RSpec as the requested sliver expiration
        //so if not yet specified, we add it here
        String modifiedRequestRspec = null;
        if (scsAuthority.hasFlag(Server.Flag.workaroundAddExpiresAttributeToRequestRspec)) {
            ModelRspec modelRspec = originalRspecRequest.getModelRspec();

            if(modelRspec == null)
                throw new JFedHighLevelException("Invalid Request: cannot parse request");

            modelRspec = modelRspec.copy();   //FEDIBBTDEV-1410 always overwrite
            modelRspec.setExpires(Date.from(requestedEndTime));
            modifiedRequestRspec = modelRspec.toGeni3Rspec();

        }

        try {
            SfaConnection con =
                    (SfaConnection) connectionProvider.getConnectionByAuthority(geniUserProvider.getLoggedInGeniUser(), scsAuthority, StitchingComputationService.class);
            StitchingComputationService.SCSReply<StitchingComputationService.ComputePathResult> res =
                    scs.computePath(con, slice.getUrnString(),
                            modifiedRequestRspec == null ? originalRspecRequest.getRspecXmlString()
                                    : modifiedRequestRspec,
                            null);

            if (res != null) {
                if (res.getValue() != null) {
                    log.info("SCS call success");
                    result = res.getValue();
                } else if (res.getOutput() != null) {
                    throw new JFedHighLevelException(String.format("SCS returned a failure: %s", res.getOutput()));
                } else {
                    throw new JFedHighLevelException("Could not process SCS response: response without value or output");
                }
            } else {
                throw new JFedHighLevelException("Could not process SCS response: is NULL");
            }
        } catch (JFedException e) {
            log.error("SCS call failed", e);
            throw e;
        }
    }

    public StitchingComputationService.ComputePathResult getResult() {
        return result;
    }
}
