/*
 * Queue - A Queueing system that can be used to handle labs in higher education
 * Copyright (C) 2016-2021  Delft University of Technology
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as
 * published by the Free Software Foundation, either version 3 of the
 * License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program.  If not, see <https://www.gnu.org/licenses/>.
 */
package nl.tudelft.queue.controller;

import static org.assertj.core.api.AssertionsForClassTypes.assertThat;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.*;

import nl.tudelft.labracore.api.dto.PersonSummaryDTO;
import nl.tudelft.labracore.lib.security.user.Person;
import nl.tudelft.queue.dto.util.ReportDTO;
import nl.tudelft.queue.model.LabRequest;
import nl.tudelft.queue.properties.MailProperties;
import nl.tudelft.queue.repository.LabRequestRepository;

import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.mockito.ArgumentCaptor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.test.mock.mockito.MockBean;
import org.springframework.mail.MailSender;
import org.springframework.mail.SimpleMailMessage;
import org.springframework.security.test.context.support.WithUserDetails;
import org.springframework.test.annotation.DirtiesContext;
import org.springframework.ui.ConcurrentModel;
import org.springframework.ui.Model;

import test.TestDatabaseLoader;
import test.labracore.*;
import test.test.TestQueueApplication;

@SpringBootTest(classes = TestQueueApplication.class)
@DirtiesContext(classMode = DirtiesContext.ClassMode.BEFORE_CLASS)
public class RequestControllerTest {
	@Autowired
	private TestDatabaseLoader db;

	@Autowired
	private PersonApiMocker personApiMocker;

	@Autowired
	private SessionApiMocker sessionApiMocker;

	@Autowired
	private EditionApiMocker editionApiMocker;

	@Autowired
	private CourseApiMocker courseApiMocker;

	@Autowired
	private ProgramApiMocker programApiMocker;

	@Autowired
	private LabRequestRepository requestRepository;

	@Autowired
	private RequestController requestController;
	@MockBean
	private MailSender mailSender;

	@Autowired
	private MailProperties mp;

	private PersonSummaryDTO student100;
	private PersonSummaryDTO student155;

	private LabRequest rq;

	private ArgumentCaptor<SimpleMailMessage> captor;

	@BeforeEach
	void setUp() {
		personApiMocker.mock();
		sessionApiMocker.mock();
		editionApiMocker.mock();
		courseApiMocker.mock();
		programApiMocker.mock();

		student100 = db.getStudents()[100];
		student155 = db.getStudents()[155];

		rq = db.getOopNowRegularLab1Requests()[1];
		sessionApiMocker.save(db.getOopNowLcSessionNow().id(rq.getSession().getId()));

		captor = ArgumentCaptor.forClass(SimpleMailMessage.class);
		doNothing().when(mailSender).send(captor.capture());
	}

	@Test
	@WithUserDetails("student155")
	void getReportPage() {
		Model model = new ConcurrentModel();
		var page = requestController.getReportPage(rq, student100.getId(), model);
		assertThat(page).isEqualTo("request/report");

		assertThat(model.getAttribute("report"))
				.isEqualTo(ReportDTO.builder().assistantName(student100.getDisplayName()).build());
		assertThat(model.getAttribute("teacher")).isExactlyInstanceOf(PersonSummaryDTO.class);
	}

	@Test
	@WithUserDetails("student155")
	void sendReport() {
		ReportDTO report = ReportDTO.builder().assistantName(student100.getDisplayName()).anonymous(false)
				.reason("my reason").build();
		Person person = new Person();
		person.setDisplayName(student155.getDisplayName());
		person.setEmail(student155.getEmail());
		var page = requestController.report(person, new String[] { "test@email.com" },
				report);

		assertThat(page).isEqualTo("redirect:/");
		verify(mailSender, atLeastOnce()).send(any(SimpleMailMessage.class));
		verify(mailSender, atMostOnce()).send(any(SimpleMailMessage.class));
		SimpleMailMessage message = captor.getValue();
		assertThat(message.getSubject()).isEqualTo("A report has been submitted through Queue");
		assertThat(message.getTo()).isEqualTo(new String[] { "test@email.com" });
		assertThat(message.getReplyTo()).isEqualTo(student155.getEmail());
	}

	@Test
	@WithUserDetails("student155")
	void sendReportAnonymous() {
		ReportDTO report = ReportDTO.builder().assistantName(student100.getDisplayName()).anonymous(true)
				.reason("my reason").build();
		Person person = new Person();
		person.setDisplayName(student155.getDisplayName());
		person.setEmail(student155.getEmail());
		var page = requestController.report(person, new String[] { "test@email.com" },
				report);

		assertThat(page).isEqualTo("redirect:/");
		verify(mailSender, atLeastOnce()).send(any(SimpleMailMessage.class));
		verify(mailSender, atMostOnce()).send(any(SimpleMailMessage.class));
		SimpleMailMessage message = captor.getValue();
		assertThat(message.getSubject()).isEqualTo("An anonymous report has been submitted " +
				"through Queue");
		assertThat(message.getReplyTo()).isEqualTo(mp.getOriginEmail());
	}
}
