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

import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;

import org.springframework.util.CollectionUtils;

import jakarta.validation.constraints.Max;
import jakarta.validation.constraints.Min;
import lombok.*;
import lombok.experimental.SuperBuilder;
import nl.tudelft.labracore.api.dto.AssignmentIdDTO;
import nl.tudelft.labracore.api.dto.SessionDetailsDTO;
import nl.tudelft.librador.dto.DTOConverter;
import nl.tudelft.queue.dto.create.QueueSessionCreateDTO;
import nl.tudelft.queue.model.embeddables.AllowedRequest;
import nl.tudelft.queue.model.enums.CommunicationMethod;
import nl.tudelft.queue.model.enums.OnlineMode;
import nl.tudelft.queue.model.enums.RequestType;
import nl.tudelft.queue.model.labs.Lab;

@Data
@SuperBuilder
@NoArgsConstructor
@AllArgsConstructor
@EqualsAndHashCode(callSuper = true)
public abstract class LabCreateDTO<D extends Lab> extends QueueSessionCreateDTO<D> {
	private CommunicationMethod communicationMethod;

	@Min(0)
	@Max(180)
	private Integer eolGracePeriod;

	@Builder.Default
	private Map<Long, Set<RequestType>> requestTypes = new HashMap<>();

	@Builder.Default
	private Set<OnlineMode> onlineModes = new HashSet<>();

	@Builder.Default
	private Boolean isBilingual = false;
	@Builder.Default
	private Boolean enableExperimental = false;

	public LabCreateDTO(SessionDetailsDTO session, D lab) {
		super(session, lab);

		communicationMethod = lab.getCommunicationMethod();

		eolGracePeriod = lab.getEolGracePeriod();

		requestTypes = lab.getAllowedRequests().stream()
				.collect(Collectors.groupingBy(AllowedRequest::getAssignment,
						Collectors.mapping(AllowedRequest::getType, Collectors.toSet())));

		this.onlineModes = new HashSet<>(lab.getOnlineModes());

		this.enableExperimental = lab.getEnableExperimental();
	}

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

		nonNull("communicationMethod", communicationMethod);

		nonEmpty("requestTypes", requestTypes);

		nonNull("enableExperimental", enableExperimental);

		if (CollectionUtils.isEmpty(rooms) && CollectionUtils.isEmpty(onlineModes)) {
			errors.rejectValue("rooms", "Select at least 1 room or online mode");
			errors.rejectValue("onlineModes", "Select at least 1 room or online mode");
		}

	}

	@Override
	protected void postApply(D data, DTOConverter converter) {
		super.postApply(data, converter);
		data.setAllowedRequestsFromMap(requestTypes);
	}

	@Override
	public List<AssignmentIdDTO> assignmentIdDTOs() {
		return requestTypes.keySet().stream()
				.map(a -> new AssignmentIdDTO().id(a))
				.collect(Collectors.toList());
	}
}
