package org.innovateuk.ifs.project.workflow.configuration;

import org.innovateuk.ifs.project.domain.Project;
import org.innovateuk.ifs.project.domain.ProjectProcess;
import org.innovateuk.ifs.project.domain.ProjectUser;
import org.innovateuk.ifs.project.repository.ProjectProcessRepository;
import org.innovateuk.ifs.project.repository.ProjectRepository;
import org.innovateuk.ifs.project.repository.ProjectUserRepository;
import org.innovateuk.ifs.project.resource.ProjectEvent;
import org.innovateuk.ifs.project.resource.ProjectState;
import org.innovateuk.ifs.user.domain.User;
import org.innovateuk.ifs.workflow.BaseWorkflowEventHandler;
import org.innovateuk.ifs.workflow.domain.ActivityType;
import org.innovateuk.ifs.workflow.repository.ProcessRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.data.repository.CrudRepository;
import org.springframework.messaging.Message;
import org.springframework.messaging.support.MessageBuilder;
import org.springframework.statemachine.config.StateMachineFactory;
import org.springframework.stereotype.Component;

/**
 * {@code ProjectWorkflowService} is the entry point for triggering the workflow.
 *
 * Based on the Project's current state, the next one is tried to transition to by triggering an event.
 *
 */
@Component
public class ProjectWorkflowHandler extends BaseWorkflowEventHandler<ProjectProcess, ProjectState, ProjectEvent, Project, ProjectUser> {

    @Autowired
    @Qualifier("projectStateMachineFactory")
    private StateMachineFactory<ProjectState, ProjectEvent> stateMachineFactory;

    @Autowired
    private ProjectProcessRepository projectProcessRepository;

    @Autowired
    private ProjectRepository projectRepository;

    @Autowired
    private ProjectUserRepository projectUserRepository;

    public boolean projectCreated(Project project, ProjectUser originalLeadApplicantProjectUser) {
        return fireEvent(projectCreatedEvent(project, originalLeadApplicantProjectUser), ProjectState.SETUP);
    }

    public boolean grantOfferLetterApproved(Project project, ProjectUser projectUser) {
        return fireEvent(mandatoryValueAddedEvent(project, projectUser, ProjectEvent.GOL_APPROVED), project);
    }

    public boolean projectWithdrawn(Project project, User internalUser) {
        return fireEvent(projectWithdrawnEvent(project, internalUser), project);
    }

    public ProjectState getState(Project project) {
        return getCurrentProcess(project).getActivityState();
    }

    @Override
    protected ProjectProcess createNewProcess(Project target, ProjectUser participant) {
        return new ProjectProcess(participant, target, null);
    }

    @Override
    protected ActivityType getActivityType() {
        return ActivityType.PROJECT_SETUP;
    }

    @Override
    protected ProcessRepository<ProjectProcess> getProcessRepository() {
        return projectProcessRepository;
    }

    @Override
    protected CrudRepository<Project, Long> getTargetRepository() {
        return projectRepository;
    }

    @Override
    protected CrudRepository<ProjectUser, Long> getParticipantRepository() {
        return projectUserRepository;
    }

    @Override
    protected StateMachineFactory<ProjectState, ProjectEvent> getStateMachineFactory() {
        return stateMachineFactory;
    }

    @Override
    protected ProjectProcess getOrCreateProcess(Message<ProjectEvent> message) {
        return getOrCreateProcessCommonStrategy(message);
    }

    private MessageBuilder<ProjectEvent> projectCreatedEvent(Project project, ProjectUser originalLeadApplicantProjectUser) {
        return MessageBuilder
                .withPayload(ProjectEvent.PROJECT_CREATED)
                .setHeader("target", project)
                .setHeader("participant", originalLeadApplicantProjectUser);
    }

    private MessageBuilder<ProjectEvent> mandatoryValueAddedEvent(Project project, ProjectUser projectUser,
                                                                  ProjectEvent event) {
        return MessageBuilder
                .withPayload(event)
                .setHeader("target", project)
                .setHeader("participant", projectUser);
    }

    private MessageBuilder<ProjectEvent> projectWithdrawnEvent(Project project, User internalUser) {
        return MessageBuilder
                .withPayload(ProjectEvent.PROJECT_WITHDRAWN)
                .setHeader("target", project)
                .setHeader("internalParticipant", internalUser);
    }
}

@@ -2395,32 +2395,28 @@
 reEvent(
-projectWithdrawn
+internalUser
 Event(pr
@@ -2434,16 +2434,48 @@
 rnalUser
+, ProjectEvent.PROJECT_WITHDRAWN
 ), proje
@@ -4347,32 +4347,28 @@
 tEvent%3E 
-projectWithdrawn
+internalUser
 Event(Pr
@@ -4391,32 +4391,52 @@
 ser internalUser
+, ProjectEvent event
 ) %7B%0A        retu
@@ -4486,38 +4486,13 @@
 oad(
-ProjectEvent.PROJECT_WITHDRAWN
+event
 )%0A  

Address review comment