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

import java.util.List;
import java.util.Optional;

import org.springframework.stereotype.Service;

import lombok.AllArgsConstructor;
import nl.tudelft.labracore.api.dto.BuildingSummaryDTO;
import nl.tudelft.labracore.api.dto.RoomDetailsDTO;
import nl.tudelft.librador.dto.DTOConverter;
import nl.tudelft.queue.cache.*;
import nl.tudelft.queue.dto.view.RequestViewDTO;
import nl.tudelft.queue.dto.view.events.RequestHandledEventViewDTO;
import nl.tudelft.queue.dto.view.requests.LabRequestViewDTO;
import nl.tudelft.queue.dto.view.requests.SelectionRequestViewDTO;
import nl.tudelft.queue.misc.DeletedObjectUtils;
import nl.tudelft.queue.model.LabRequest;
import nl.tudelft.queue.model.Request;
import nl.tudelft.queue.model.RequestEvent;
import nl.tudelft.queue.model.SelectionRequest;

@Service
@AllArgsConstructor
public class RequestViewDTOService {

	private final RequestEventViewDTOService requestEventViewDTOService;

	private final AssignmentCacheManager assignmentCache;
	private final EditionCacheManager editionCache;
	private final EditionCollectionCacheManager editionCollectionCache;
	private final ModuleCacheManager moduleCache;
	private final PersonCacheManager personCache;
	private final RoomCacheManager roomCache;
	private final SessionCacheManager sessionCache;
	private final StudentGroupCacheManager groupCache;

	private final DTOConverter converter;

	public LabRequestViewDTO convert(LabRequest request) {
		return (LabRequestViewDTO) convert((Request<?>) request);
	}

	public List<LabRequestViewDTO> convert(List<LabRequest> requests) {
		return requests.stream().map(this::convert).toList();
	}

	@SuppressWarnings("unchecked")
	public <R extends Request<?>> RequestViewDTO<?> convert(R request) {
		RequestViewDTO<R> view = converter.convert(request, (Class<RequestViewDTO<R>>) request.viewClass());

		view.setRoom(roomCache.get(request.getRoom()).orElse(new RoomDetailsDTO().id(-1L)
				.abbreviation("").name("To be determined").building(new BuildingSummaryDTO().name("TBD"))));
		view.setRequester(personCache.getRequired(request.getRequester()));
		view.setSession(sessionCache.getRequired(request.getSession().getSession()));
		view.setStudentGroup(groupCache.get(request.getStudentGroup())
				.orElse(DeletedObjectUtils.studentGroupDetailsDTO()));

		if (view.getSession().getEdition() != null) {
			view.setEdition(editionCache.getRequired(view.getSession().getEdition().getId()));
		} else if (!view.getSession().getEditions().isEmpty()) {
			view.setEditionCollection(
					editionCollectionCache.getRequired(view.getSession().getEditionCollection().getId()));
		}

		if (request.getEventInfo().getAssignedTo() != null) {
			view.getEventInfo()
					.setAssignedTo(personCache.getRequired(request.getEventInfo().getAssignedTo()));
		}

		view.setEvents(request.getEventInfo().getEvents().stream()
				.map(event -> (RequestEvent<R>) event)
				.map(requestEventViewDTOService::convert)
				.toList());

		switch (request) {
			case LabRequest lr -> setLabRequestViewAttributes(lr, (LabRequestViewDTO) view);
			case SelectionRequest sr -> setSelectionRequestViewAttributes(sr, (SelectionRequestViewDTO) view);
			default -> {
			}
		}

		return view;
	}

	private void setLabRequestViewAttributes(LabRequest request, LabRequestViewDTO view) {
		view.setAssignment(assignmentCache.get(request.getAssignment())
				.orElse(DeletedObjectUtils.assignmentDetailsDTO()));

		if (view.getEdition() == null) {
			Long editionId = moduleCache.getRequired(view.getAssignment().getModule().getId()).getEdition()
					.getId();
			view.setEdition(editionCache.getRequired(editionId));
		}

		Optional<RequestHandledEventViewDTO<?>> handledEvent = view.getEvents().stream()
				.filter(e -> e instanceof RequestHandledEventViewDTO<?>)
				.findFirst()
				.map(e -> (RequestHandledEventViewDTO<?>) e);
		if (handledEvent.isPresent()) {
			view.setCommentForStudent(handledEvent.get().getReasonForStudent());
			view.setCommentForAssistant(handledEvent.get().getReasonForAssistant());
		} else {
			view.setCommentForStudent("");
			view.setCommentForAssistant("");
		}
	}

	private void setSelectionRequestViewAttributes(SelectionRequest request, SelectionRequestViewDTO view) {

	}

}
