class ApplicationTeamPopulator {

    public ApplicationTeamViewModel populate(long applicationId, long questionId, UserResource user) {
        ApplicationResource application = applicationService.getById(applicationId);
        CompetitionResource competition = competitionRestService.getCompetitionById(application.getCompetition()).getSuccess();
        List<ProcessRoleResource> processRoles = userRestService.findProcessRole(applicationId).getSuccess();
        List<ProcessRoleResource> applicantProcessRoles = processRoles
                .stream()
                .filter(role -> applicantProcessRoles().contains(role.getRole()))
                .collect(toList());
        List<InviteOrganisationResource> inviteOrganisationResources = inviteRestService.getInvitesByApplication(applicationId).getSuccess();
        List<OrganisationResource> organisations = organisationRestService.getOrganisationsByApplicationId(applicationId).getSuccess();
        List<QuestionStatusResource> questionStatuses = questionStatusRestService.findQuestionStatusesByQuestionAndApplicationId(questionId, applicationId).getSuccess();

        boolean leadApplicant = applicantProcessRoles.stream()
                .anyMatch(pr -> pr.getUser().equals(user.getId()) && pr.getRole() == LEADAPPLICANT);

        Multimap<Long, ProcessRoleResource> organisationToProcessRole = index(applicantProcessRoles, ProcessRoleResource::getOrganisationId);
        Map<Long, InviteOrganisationResource> organisationToInvite = inviteOrganisationResources.stream()
                .filter(organisationInvite -> organisationInvite.getOrganisation() != null)
                .collect(toMap(InviteOrganisationResource::getOrganisation, Function.identity()));

        List<ApplicationTeamOrganisationViewModel> organisationViewModels = organisations.stream()
                .map(organisation -> toOrganisationTeamViewModel(applicationId, organisation, organisationToProcessRole.get(organisation.getId()), organisationToInvite.get(organisation.getId()), leadApplicant, user))
                .collect(toList());

        organisationViewModels.addAll(inviteOrganisationResources.stream()
            .filter(invite -> invite.getOrganisation() == null)
            .map(invite -> toInviteOrganisationTeamViewModel(invite, leadApplicant))
            .collect(toList()));

        sort(organisationViewModels);

        ProcessRoleResource ktaProcessRole = null;
        ApplicationKtaInviteResource ktaInvite = null;

        Optional<ProcessRoleResource> kta = processRoles.stream()
                .filter(pr -> pr.getRole() == KNOWLEDGE_TRANSFER_ADVISER).findAny();

        if (kta.isPresent()) {
            ktaProcessRole = kta.get();
        } else {
            ktaInvite = applicationKtaInviteRestService.getKtaInviteByApplication(applicationId).getSuccess();
        }

        return new ApplicationTeamViewModel(applicationId, application.getName(), application.getCompetitionName(), questionId, organisationViewModels, user.getId(),
                leadApplicant,
                competition.getCollaborationLevel() == CollaborationLevel.SINGLE,
                application.isOpen() && competition.isOpen(),
                questionStatuses.stream().anyMatch(QuestionStatusResource::getMarkedAsComplete),
                competition.isKtp(),
                ktaInvite, ktaProcessRole);
    }

}