package be.iminds.ilabt.jfed.highlevel.jobs.states;

import be.iminds.ilabt.jfed.experiment.Experiment;
import be.iminds.ilabt.jfed.experiment.tasks.ExperimentTaskStatus;
import be.iminds.ilabt.jfed.highlevel.jobs.Job;
import be.iminds.ilabt.jfed.highlevel.jobs.State;
import be.iminds.ilabt.jfed.highlevel.model.SfaModel;
import be.iminds.ilabt.jfed.highlevel.model.UserSpecHelper;
import be.iminds.ilabt.jfed.lowlevel.GeniUser;
import be.iminds.ilabt.jfed.lowlevel.GeniUserProvider;
import be.iminds.ilabt.jfed.lowlevel.GeniUserWithSpeaksFor;
import be.iminds.ilabt.jfed.lowlevel.api.user_spec.UserSpec;
import be.iminds.ilabt.jfed.rspec.model.DistributeSshKeypair;
import be.iminds.ilabt.jfed.rspec.model.ModelRspecType;
import be.iminds.ilabt.jfed.rspec.model.impl.BasicDistributeSshKeypair;
import be.iminds.ilabt.jfed.rspec.model.javafx_impl.FXModelRspec;
import be.iminds.ilabt.jfed.util.GeniUrn;
import be.iminds.ilabt.jfed.util.KeyUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.annotation.Nonnull;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.NoSuchAlgorithmException;
import java.security.interfaces.RSAPublicKey;
import java.util.List;

/**
 * User: twalcari
 * Date: 12/4/2015
 * Time: 14:42
 */
public class CreateUserSpecListState extends State {
    private static final Logger LOG = LoggerFactory.getLogger(CreateUserSpecListState.class);
    private List<UserSpec> userSpecs = null;

    private final Experiment experiment;
    private final GeniUserProvider geniUserProvider;
    private final SfaModel sfaModel;

    protected CreateUserSpecListState(Experiment experiment, GeniUserProvider geniUserProvider, SfaModel sfaModel) {
        super("Gathering experiment members info");
        this.experiment = experiment;
        this.geniUserProvider = geniUserProvider;
        this.sfaModel = sfaModel;
    }

    @Nonnull
    @Override
    public ExperimentTaskStatus executeState(Job<?> job) throws InterruptedException {
        assert experiment.getSlice().getRequestRspec() != null;
        userSpecs = UserSpecHelper.getMergedUserSpecs(geniUserProvider, sfaModel,
                experiment.getSlice().getRequestRspec().getModelRspec());

        userSpecs = UserSpecHelper.mergeUserSpecs(userSpecs, experiment.getUserSpecs());

//
//        if (experiment.isIncludeProjectMemberSshKeys())
//            userSpecs = UserSpecHelper.mergeUserSpecs(userSpecs,
//                    UserSpecHelper.getSliceMemberUserSpecs(experiment.getSlice().getUrn(), sfaModel));


        FXModelRspec rspec = experiment.getSlice().getRequestRspec().getModelRspec(ModelRspecType.FX);
        if (rspec != null) {
            for (DistributeSshKeypair distributeSshKeypair : rspec.getDistributeSshKeypairs()) {
                GeniUrn user = distributeSshKeypair.getUser();
                if (user == null) {
                    //default to logged in user, or if he speaks for someone, the user spoken for.
                    GeniUser geniUser = geniUserProvider.getLoggedInGeniUser();
                    GeniUserWithSpeaksFor geniUserWithSpeaksFor =
                            (geniUser instanceof GeniUserWithSpeaksFor)
                                    ? (GeniUserWithSpeaksFor) geniUser : null;
                    if (geniUserWithSpeaksFor != null) {
                        user = geniUserWithSpeaksFor.getSpeaksForUrn();
                    } else {
                        user = geniUser.getUserUrn();
                    }
                }

                //make a new object with potentially new user in
                final BasicDistributeSshKeypair distributeSshKeypairWithAdaptedUser =
                        new BasicDistributeSshKeypair(distributeSshKeypair.getLocation(), user);

                try {
                    KeyPairGenerator keyGen = KeyPairGenerator.getInstance("RSA");
                    keyGen.initialize(2048);
                    KeyPair keyPair = keyGen.generateKeyPair();
                    experiment.getKeypairs().put(distributeSshKeypairWithAdaptedUser, keyPair);
                    RSAPublicKey publicKey = (RSAPublicKey) keyPair.getPublic();

                    userSpecs =
                            UserSpecHelper.addUserSpec(userSpecs, new UserSpec(user.toString(),
                                    KeyUtil.rsaPublicKeyToOpenSshAuthorizedKeysFormat(publicKey)));
                } catch (NoSuchAlgorithmException ex) {
                    LOG.error("Could not generate keypairs to distribute: {}", ex.getMessage(), ex);
                }
            }


        }

        return ExperimentTaskStatus.SUCCESS;
    }

    public List<UserSpec> getUserSpecs() {
        return userSpecs;
    }
}
