package be.iminds.jfed.gts_highlevel.tasks;

import be.iminds.ilabt.jfed.highlevel.controller.TaskExecution;
import be.iminds.ilabt.jfed.util.JavaFXLogger;
import be.iminds.jfed.gts_highlevel.controller.GtsException;
import be.iminds.jfed.gts_highlevel.controller.GtsModel;
import be.iminds.jfed.gts_highlevel.controller.GtsReservationManager;
import be.iminds.jfed.gts_highlevel.controller.GtsReservationManagerFactory;
import be.iminds.jfed.gts_highlevel.model.GtsXmlProject;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.inject.Provider;
import java.util.List;
import java.util.Objects;

/**
 * User: twalcari
 * Date: 9/25/2015
 * Time: 09:56
 */
public class CreateGtsProjectTask extends LoggedInGtsTask {
    private static final Logger LOG = LoggerFactory.getLogger(CreateGtsProjectTask.class);

    private final String projectName;
    private final String vpnUsername;
    private final String vpnPassword;
    private final List<String> users;

    private GtsXmlProject project = null;

    CreateGtsProjectTask(String projectName, String vpnUsername, String vpnPassword, List<String> users,
                                GtsReservationManagerFactory gtsReservationManagerFactory,
                                Provider<GtsLoginTask> loginGtsTaskProvider,
                                GtsModel gtsModel, JavaFXLogger logger) {
        super("Creating GTS project '" + projectName + "'",logger, gtsReservationManagerFactory, loginGtsTaskProvider, gtsModel);
        this.projectName = projectName;
        this.vpnUsername = vpnUsername;
        this.vpnPassword = vpnPassword;
        this.users = users;
    }

    @Override
    protected void doGtsRMTask(TaskExecution taskExecution, GtsReservationManager reservationManager) throws GtsException {
        List<GtsXmlProject> existingProjects = reservationManager.listProjects();

        String newProjectName = findNewProjectName(existingProjects, projectName);

        GtsXmlProject newProject = new GtsXmlProject();
        newProject.setId(newProjectName);
        newProject.setVpnUser(vpnUsername);
        newProject.setVpnPassword(vpnPassword);
        newProject.setUserLogins(users);

        try {
            LOG.trace("Creating new project '{}'", newProject);
            reservationManager.addProject(newProject);
            //We got here without errors: copy requested project into result object

            existingProjects = reservationManager.listProjects();

            project = existingProjects.stream().filter(ep -> Objects.equals(ep.getId(), newProjectName)).findFirst()
                    .orElseThrow(() -> new GtsException("Could not find newly created project when querying all projects"));

            LOG.debug("Successfully created project {}", newProjectName);
        } catch (GtsException ex) {
            //do a rollback
            LOG.warn("Could not create new project {}. Performing cleanup.", newProjectName);

            try {
                reservationManager.removeProject(newProjectName);
                LOG.info("Successfully removed project {} during rollback.", newProjectName);
            } catch (GtsException ex2) {
                LOG.info("Could not remove project {} during rollback. Creating it had probably failed too.", newProjectName, ex2);
            }

            throw ex;
        }

    }

    public GtsXmlProject getProject() {
        return project;
    }

    private static String findNewProjectName(List<GtsXmlProject> existingProjects, String projectName) {
        int suffix = 0;
        String newProjectName = projectName;

        while (containsProjectName(existingProjects, newProjectName)) {
            suffix++;
            newProjectName = projectName + "_" + suffix;
        }
        return newProjectName;
    }

    private static boolean containsProjectName(List<GtsXmlProject> projects, String newProjectName) {
        return projects.stream().anyMatch(gtsProject -> Objects.equals(newProjectName, gtsProject.getId()));
    }

}
