/*
 * 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 test.labracore;

import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.when;

import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.stream.Collectors;

import org.modelmapper.ModelMapper;

import com.google.common.base.Predicates;
import com.google.common.collect.Maps;

import lombok.AllArgsConstructor;
import nl.tudelft.labracore.api.AssignmentControllerApi;
import nl.tudelft.labracore.api.dto.*;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;

@AllArgsConstructor
public class AssignmentApiMocker extends LabracoreApiMocker<AssignmentDetailsDTO, Long> {
	private final AssignmentControllerApi aApi;

	private final Map<Long, AssignmentModuleDetailsDTO> assignmentsWithModules = new HashMap<>();

	@Override
	public void mock() {
		when(aApi.getAllAssignmentsById(any())).thenAnswer(getAllByIds);

		when(aApi.getAssignmentById(any())).thenReturn(Mono.empty());

		when(aApi.getAssignmentsWithModules(any())).thenAnswer(invocation -> {
			List<Long> ids = invocation.getArgument(0);
			return Flux.fromIterable(Maps.filterKeys(assignmentsWithModules, Predicates.in(ids)).values());
		});

		when(aApi.getAllAssignments()).thenAnswer(invocation -> {
			var mapper = new ModelMapper();
			var summaries = data.values().stream()
					.map(dto -> mapper.map(dto, AssignmentSummaryDTO.class))
					.collect(Collectors.toList());

			return Flux.fromIterable(summaries);
		});
	}

	@Override
	public AssignmentDetailsDTO save(AssignmentDetailsDTO dto) {
		super.save(dto);

		var assignmentWithModule = mapper.map(dto, AssignmentModuleDetailsDTO.class);

		assignmentsWithModules.put(Objects.requireNonNull(dto.getId()), assignmentWithModule);

		return dto;
	}

	@Override
	public Long getId(AssignmentDetailsDTO dto) {
		return dto.getId();
	}

	public void initializeAssignmentWithModule(long assignmentId, ModuleDetailsDTO module) {
		var moduleSummary = Objects.requireNonNull(assignmentsWithModules.get(assignmentId));

		var mappedModule = mapper.map(module, ModuleLayer1DTO.class);

		moduleSummary.setModule(mappedModule);
	}
}
