/*
 * Queue - A Queueing system that can be used to handle labs in higher education
 * Copyright (C) 2016-2024  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.service.mail;

import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.ArgumentMatchers.anyLong;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;

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 jakarta.transaction.Transactional;
import nl.tudelft.labracore.api.PersonControllerApi;
import nl.tudelft.labracore.api.dto.PersonDetailsDTO;
import nl.tudelft.labracore.lib.security.user.DefaultRole;
import nl.tudelft.labracore.lib.security.user.Person;
import nl.tudelft.queue.dto.create.CourseRequestCreateDTO;
import nl.tudelft.queue.dto.create.reporting.AcademicCounsellorReportDTO;
import nl.tudelft.queue.dto.create.reporting.ConfidentialAdvisorsReportDTO;
import nl.tudelft.queue.dto.create.reporting.ReportDTO;
import nl.tudelft.queue.properties.MailProperties;
import nl.tudelft.queue.properties.QueueProperties;
import reactor.core.publisher.Mono;
import test.test.TestQueueApplication;

@Transactional
@SpringBootTest(classes = TestQueueApplication.class)
public class MailServiceTest {
	@Autowired
	private MailServiceProdImpl ms;

	@Autowired
	private QueueProperties qp;

	@Autowired
	private MailProperties mp;

	@Autowired
	private PersonControllerApi personApi;

	@MockBean
	private MailSender mailSender;

	private final Person person = Person.builder()
			.id(8932L)
			.defaultRole(DefaultRole.ADMIN)
			.displayName("Mr. Admin")
			.email("admin@tudelft.nl")
			.username("adminnnn")
			.build();

	private final CourseRequestCreateDTO dto = CourseRequestCreateDTO.builder()
			.name("Test Course")
			.code("TEST10")
			.build();

	private ArgumentCaptor<SimpleMailMessage> msgArg;

	@BeforeEach
	void setUp() {
		msgArg = ArgumentCaptor.forClass(SimpleMailMessage.class);
	}

	@Test
	void sendCourseEmailGoesToSupportEmail() {
		ms.sendCourseRequest(person, dto);

		verify(mailSender).send(msgArg.capture());

		assertThat(msgArg.getValue().getTo()).containsOnly(mp.getSupportEmail());
	}

	@Test
	void sendCourseEmailComesFromOriginMail() {
		ms.sendCourseRequest(person, dto);

		verify(mailSender).send(msgArg.capture());

		assertThat(msgArg.getValue().getFrom()).isEqualTo(mp.getOriginEmail());
	}

	@Test
	void sendCourseEmailSubjectContainsCourseName() {
		ms.sendCourseRequest(person, dto);

		verify(mailSender).send(msgArg.capture());

		assertThat(msgArg.getValue().getSubject()).contains(dto.getName());
	}

	@Test
	void sendCourseEmailTextContainsUserInfo() {
		ms.sendCourseRequest(person, dto);

		verify(mailSender).send(msgArg.capture());

		assertThat(msgArg.getValue().getText()).contains(person.getDisplayName());
		assertThat(msgArg.getValue().getText()).contains(person.getEmail());
	}

	@Test
	void sendCourseEmailTextContainsLink() {
		ms.sendCourseRequest(person, dto);

		verify(mailSender).send(msgArg.capture());

		assertThat(msgArg.getValue().getText()).contains(qp.getDeployUrl());
	}

	@Test
	void sendCourseEmailReplyToContainsUserEmail() {
		ms.sendCourseRequest(person, dto);

		verify(mailSender).send(msgArg.capture());

		assertThat(msgArg.getValue().getReplyTo()).isEqualTo(person.getEmail());
	}

	@Test
	void createReportEmailTestOnlyAcademicCounsellor() {
		when(personApi.getPersonById(anyLong())).thenReturn(Mono.just(new PersonDetailsDTO().displayName("reported")));

		ReportDTO dto = AcademicCounsellorReportDTO.builder().academicCounsellorEmail(
				"academicCounsellor").mailToStudyAssoc(false).reportedId(1L)
				.description("desc").build();

		var message = ms.createReportMail(dto,
				Person.builder().displayName("displayname").email("email").build());
		assertThat(message.getSubject()).isEqualTo("A new report was filed in Queue");
		assertThat(message.getTo()).containsOnly("academicCounsellor");
	}

	@Test
	void createReportEmailTestAcademicCounsellorAndStudy() {
		when(personApi.getPersonById(anyLong())).thenReturn(Mono.just(new PersonDetailsDTO().displayName("reported")));

		ReportDTO dto = AcademicCounsellorReportDTO.builder().academicCounsellorEmail(
				"academicCounsellor").mailToStudyAssoc(true)
				.studyAssocMail("studyAssoc").reportedId(1L).description("desc").build();

		var message = ms.createReportMail(dto,
				Person.builder().displayName("displayname").email("email").build());
		assertThat(message.getSubject()).isEqualTo("A new report was filed in Queue");
		assertThat(message.getTo()).containsOnly("academicCounsellor", "studyAssoc");
	}

	@Test
	void createReportEmailTestConfidential() {
		when(personApi.getPersonById(anyLong())).thenReturn(Mono.just(new PersonDetailsDTO().displayName("reported")));

		ReportDTO dto = ConfidentialAdvisorsReportDTO.builder().trusteeMail(
				"trustee").reportedId(1L)
				.description("desc").build();

		var message = ms.createReportMail(dto,
				Person.builder().displayName("displayname").email("email").build());
		assertThat(message.getSubject()).isEqualTo("A new report was filed in Queue");
		assertThat(message.getTo()).containsOnly("trustee");
	}
}
