package de.tum.in.www1.artemis.programmingexercise.simulation;

import static de.tum.in.www1.artemis.web.rest.ProgrammingSubmissionResultSimulationResource.Endpoints.*;
import static org.assertj.core.api.Assertions.assertThat;

import java.util.List;
import java.util.stream.Collectors;

import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.security.test.context.support.WithMockUser;

import de.tum.in.www1.artemis.AbstractSpringDevelopmentTest;
import de.tum.in.www1.artemis.domain.ProgrammingExercise;
import de.tum.in.www1.artemis.domain.ProgrammingSubmission;
import de.tum.in.www1.artemis.domain.Result;
import de.tum.in.www1.artemis.domain.enumeration.SubmissionType;
import de.tum.in.www1.artemis.domain.participation.Participation;
import de.tum.in.www1.artemis.repository.*;

public class ProgrammingExerciseSubmissionAndResultSimulationIntegrationTest extends AbstractSpringDevelopmentTest {

    @Autowired
    ProgrammingSubmissionRepository submissionRepository;

    @Autowired
    ParticipationRepository participationRepository;

    @Autowired
    ProgrammingExerciseRepository programmingExerciseRepository;

    @Autowired
    ResultRepository resultRepository;

    private List<Long> participationIds;

    private Long exerciseId;

    private ProgrammingExercise exercise;

    @BeforeEach
    void setUp() {
        database.addUsers(3, 2, 0, 2);
        database.addCourseWithOneProgrammingExerciseAndTestCases();

        exercise = programmingExerciseRepository.findAllWithEagerParticipationsAndLegalSubmissions().get(0);
        database.addStudentParticipationForProgrammingExercise(exercise, "student1");
        database.addStudentParticipationForProgrammingExercise(exercise, "student2");

        exerciseId = exercise.getId();
        exercise = programmingExerciseRepository.findAllWithEagerParticipationsAndLegalSubmissions().get(0);
        participationIds = exercise.getStudentParticipations().stream().map(Participation::getId).collect(Collectors.toList());
    }

    @AfterEach
    public void tearDown() {
        database.resetDatabase();
    }

    /**
     * This tests if the submission is created for programming exercises without local setup
     */

    @Test
    @WithMockUser(username = "instructor1", roles = "INSTRUCTOR")
    void shouldCreateSubmissionWithoutConnectionToVCSandCI() throws Exception {
        assertThat(submissionRepository.findAll()).hasSize(0);
        final var returnedSubmission = request.postWithResponseBody(ROOT + SUBMISSIONS_SIMULATION.replace("{exerciseId}", String.valueOf(exerciseId)), null,
                ProgrammingSubmission.class, HttpStatus.CREATED);
        assertThat(submissionRepository.findAll()).hasSize(1);
        ProgrammingSubmission submission = submissionRepository.findAll().get(0);
        assertThat(returnedSubmission).isEqualTo(submission);
        assertThat(participationRepository.findById(submission.getParticipation().getId()));
        assertThat(participationIds.contains(submission.getParticipation().getId()));
        assertThat(submission.getType()).isEqualTo(SubmissionType.MANUAL);
        assertThat(submission.isSubmitted()).isTrue();
    }

    /**
     * This tests if the result is created for programming exercises without local setup
     */

    @Test
    @WithMockUser(username = "instructor1", roles = "INSTRUCTOR")
    void shouldCreateResultWithoutConnectionToVCSandCI() throws Exception {
        final var returnedSubmission = request.postWithResponseBody(ROOT + SUBMISSIONS_SIMULATION.replace("{exerciseId}", String.valueOf(exerciseId)), null,
                ProgrammingSubmission.class, HttpStatus.CREATED);
        assertThat(resultRepository.findAll()).hasSize(0);
        Result returnedResult = request.postWithResponseBody(ROOT + RESULTS_SIMULATION.replace("{exerciseId}", String.valueOf(exerciseId)), null, Result.class, HttpStatus.CREATED);
        ProgrammingSubmission submission = submissionRepository.findAll().get(0);
        assertThat(returnedSubmission).isEqualTo(submission);
        assertThat(resultRepository.findAll()).hasSize(1);
        Result result = resultRepository.findAll().get(0);
        assertThat(returnedResult).isEqualTo(result);
        assertThat(result.getParticipation().getId()).isEqualTo(submission.getParticipation().getId());
    }
}

@@ -1555,17 +1555,17 @@
 s(3, 2, 
-0
+1
 , 2);%0A  
@@ -2382,33 +2382,32 @@
 l setup%0A     */%0A
-%0A
     @Test%0A    @W
@@ -2422,39 +2422,35 @@
 ser(username = %22
-instruc
+edi
 tor1%22, roles = %22
@@ -2441,39 +2441,35 @@
 tor1%22, roles = %22
-INSTRUC
+EDI
 TOR%22)%0A    void s
@@ -2607,35 +2607,53 @@
 ;%0A        final 
-var
+ProgrammingSubmission
  returnedSubmiss
@@ -3357,32 +3357,469 @@
 sTrue();%0A    %7D%0A%0A
+    // The tutor has the editor role, but does not have the permissions for the repository since the tutor is not part of the editor group.%0A    @Test%0A    @WithMockUser(username = %22tutor1%22, roles = %22EDITOR%22)%0A    void shouldCreateSubmissionWithoutConnectionToVCSandCI_forbidden() throws Exception %7B%0A        request.post(ROOT + SUBMISSIONS_SIMULATION.replace(%22%7BexerciseId%7D%22, String.valueOf(exerciseId)), null, HttpStatus.FORBIDDEN);%0A    %7D%0A%0A
     /**%0A     * T
@@ -3907,17 +3907,16 @@
      */%0A
-%0A
     @Tes
@@ -3951,15 +3951,11 @@
  = %22
-instruc
+edi
 tor1
@@ -3970,15 +3970,11 @@
  = %22
-INSTRUC
+EDI
 TOR%22
@@ -4069,11 +4069,29 @@
 nal 
-var
+ProgrammingSubmission
  ret
@@ -4848,16 +4848,16 @@
 esult);%0A
-
         
@@ -4957,11 +4957,440 @@
 );%0A    %7D
+%0A%0A    // The tutor has the editor role, but does not have the permissions for the repository since the tutor is not part of the editor group.%0A    @Test%0A    @WithMockUser(username = %22tutor1%22, roles = %22EDITOR%22)%0A    void shouldCreateResultWithoutConnectionToVCSandCI_forbidden() throws Exception %7B%0A        request.post(ROOT + RESULTS_SIMULATION.replace(%22%7BexerciseId%7D%22, String.valueOf(exerciseId)), null, HttpStatus.FORBIDDEN);%0A    %7D
 %0A%7D%0A

Improve server test coverage: ProgrammingSubmisionResultSimulationResource (#3388)