/*
 * 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;

import static nl.tudelft.labracore.api.dto.RolePersonDetailsDTO.TypeEnum.*;
import static nl.tudelft.labracore.api.dto.RolePersonDetailsDTO.TypeEnum.TA;
import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.Mockito.*;

import java.util.List;
import java.util.Set;

import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.mockito.ArgumentCaptor;
import org.mockito.Captor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.test.mock.mockito.SpyBean;

import jakarta.transaction.Transactional;
import nl.tudelft.labracore.api.AssignmentControllerApi;
import nl.tudelft.labracore.api.EditionControllerApi;
import nl.tudelft.labracore.api.SessionControllerApi;
import nl.tudelft.labracore.api.dto.*;
import nl.tudelft.queue.model.LabRequest;
import nl.tudelft.queue.model.enums.RequestType;
import nl.tudelft.queue.model.labs.RegularLab;
import nl.tudelft.queue.realtime.messages.RequestCreatedMessage;
import reactor.core.publisher.Mono;
import test.TestDatabaseLoader;
import test.test.TestQueueApplication;

@Transactional
@SpringBootTest(classes = TestQueueApplication.class)
public class WebSocketServiceTest {

	@Autowired
	private TestDatabaseLoader db;
	@SpyBean
	private WebSocketService wss;

	@Autowired
	private AssignmentControllerApi aApi;

	@Autowired
	private EditionControllerApi eApi;

	@Autowired
	private SessionControllerApi sApi;

	private EditionDetailsDTO oopNow;

	@Captor
	private ArgumentCaptor<List<PersonSummaryDTO>> peopleCaptor;

	RegularLab rlOopNowSharedLab;

	AssignmentDetailsDTO oopAssignment1;

	LabRequest sharedLabRequest;

	AssignmentModuleDetailsDTO oopAssignment1ModuleDetails;

	@BeforeEach
	void setup() {

		db.mockAll();

		oopNow = db.getOopNow();
		oopAssignment1 = db.getOopNowAssignments()[0];
		rlOopNowSharedLab = db.getRlOopNowSharedLab();

		sharedLabRequest = LabRequest.builder()
				.requestType(RequestType.SUBMISSION)
				.assignment(oopAssignment1.getId())
				.question("Sample Question asdfasfsadfsa")
				.room(db.getRoomCz1().getId())
				.session(db.getRlOopNowSharedLab())
				.requester(db.getOopNowStudents()[0].getId().getPersonId())
				.build();

		oopAssignment1ModuleDetails = new AssignmentModuleDetailsDTO()
				.id(oopAssignment1.getId())
				.module(new ModuleLayer1DTO()
						.edition(new EditionSummaryDTO().id(db.getOopNow().getId())));

	}

	@Test
	void websocketMessageGetsSentToCorrectPeople() {
		var oopImportantPeople = eApi.getEditionParticipants(oopNow.getId())
				.collectList()
				.block()
				.stream()
				.filter(r -> r != null && Set.of(TEACHER, TEACHER_RO, HEAD_TA, TA).contains(r.getType()))
				.map(RolePersonDetailsDTO::getPerson)
				.distinct()
				.toList();

		var apiReturn = Mono.just(oopAssignment1ModuleDetails);
		when(aApi.getAssignmentById(any())).thenReturn(apiReturn);

		wss.sendRequestTableMessage(sharedLabRequest, new RequestCreatedMessage()).join();

		verify(sApi, never()).getSessionsById(any());
		verify(aApi, times(1)).getAssignmentById(oopAssignment1.getId());

		verify(wss, times(1)).sendMessage(peopleCaptor.capture(), eq("/topic/request-table"),
				eq(new RequestCreatedMessage()));
		assertThat(peopleCaptor.getValue()).containsExactlyInAnyOrderElementsOf(oopImportantPeople);

	}

}
