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

import static nl.tudelft.librador.SpringContext.getBean;

import java.util.Objects;

import javax.validation.constraints.NotNull;
import javax.validation.constraints.Size;

import lombok.*;
import lombok.experimental.SuperBuilder;
import nl.tudelft.queue.cache.AssignmentCacheManager;
import nl.tudelft.queue.cache.SessionCacheManager;
import nl.tudelft.queue.dto.create.RequestCreateDTO;
import nl.tudelft.queue.dto.id.TimeSlotIdDTO;
import nl.tudelft.queue.model.LabRequest;
import nl.tudelft.queue.model.embeddables.AllowedRequest;
import nl.tudelft.queue.model.enums.Language;
import nl.tudelft.queue.model.enums.OnlineMode;
import nl.tudelft.queue.model.enums.RequestType;
import nl.tudelft.queue.model.labs.Lab;
import nl.tudelft.queue.model.labs.SlottedLab;

@Data
@SuperBuilder
@NoArgsConstructor
@AllArgsConstructor
@EqualsAndHashCode(callSuper = true)
public class LabRequestCreateDTO extends RequestCreateDTO<LabRequest, Lab> {

	@NotNull
	private RequestType requestType;

	@Size(max = 250)
	private String comment;

	@Size(max = 500)
	private String question;

	private TimeSlotIdDTO timeSlot;

	@NotNull
	private Long assignment;

	private Long room;

	private OnlineMode onlineMode;

	@Builder.Default
	private Language language = Language.ANY;

	private transient Lab session;

	@Override
	public void validate() {
		super.validate();

		if (requestType == RequestType.QUESTION) {
			nonEmpty("question", question);
		}

		if ((room == null) == (onlineMode == null)) {
			errors.rejectValue("room", "Room or online mode not selected");
			errors.rejectValue("onlineMode", "Room or online mode not selected");
		}

		var session = getBean(SessionCacheManager.class).getRequired(this.getSession().getSession());
		if (room != null && session.getRooms().stream().noneMatch(r -> Objects.equals(r.getId(), room))) {
			errors.rejectValue("room", "A room with id " + room + " is not available in the lab.");
		}

		if (!this.session.getAllowedRequests().contains(new AllowedRequest(assignment, requestType))) {
			errors.rejectValue("assignment", "Incompatible assignment for request type " + requestType);
		}

		if (this.session instanceof SlottedLab &&
				(timeSlot == null || !Objects.equals(timeSlot.apply().getLab().getId(), this.session.getId())
						||
						timeSlot.apply().isFull())) {
			errors.rejectValue("slot", "No time slot selected for request");
		}
	}

	@Override
	public Long getModule() {
		return getBean(AssignmentCacheManager.class).getRequired(assignment)
				.getModule().getId();
	}

	@Override
	public Class<LabRequest> clazz() {
		return LabRequest.class;
	}
}
