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

import org.springframework.stereotype.Service;

import jakarta.transaction.Transactional;
import lombok.AllArgsConstructor;
import nl.tudelft.labracore.api.dto.RoomDetailsDTO;
import nl.tudelft.labracore.api.dto.SessionDetailsDTO;
import nl.tudelft.queue.cache.RoomCacheManager;
import nl.tudelft.queue.cache.SessionCacheManager;
import nl.tudelft.queue.dto.create.QueueSessionCreateDTO;
import nl.tudelft.queue.model.*;
import nl.tudelft.queue.repository.QueueSessionRepository;

@Service
@AllArgsConstructor
public class SessionService {

	private final SessionCacheManager sessionCacheManager;

	private final LabRequestConstraintService labRequestConstraintService;

	private final RoomCacheManager roomCacheManager;

	private final QueueSessionRepository queueSessionRepository;

	public SessionDetailsDTO getSessionDTOFromSession(QueueSession<?> session) {
		return sessionCacheManager.getRequired(session.getSession());
	}

	/**
	 * Checks whether the given request is allowed according to the restrictions of this lab.
	 *
	 * @param  session The session for which to check.
	 * @param  request The request to check for whether it is allowed to be posted.
	 * @return         Whether the given request should be allowed.
	 */
	public boolean allowsRequest(QueueSession<?> session, Request<?> request) {
		return labRequestConstraintService.allowsRequest(session.getConstraints(), request)
				&& Objects.equals(request.getSession().getId(), session.getId());
	}

	/**
	 * @return Room details objects representing the currently selected rooms.
	 */
	public List<RoomDetailsDTO> roomDetails(QueueSessionCreateDTO<?> dto) {
		return roomCacheManager.getAndIgnoreMissing(new ArrayList<>(dto.getRooms()));
	}

	/**
	 * Gets a session from core and deletes the local session data if the core session does not exist.
	 *
	 * @param  sessionId The id of the session
	 * @return           The session details
	 */
	public SessionDetailsDTO getCoreSession(Long sessionId) {
		return sessionCacheManager.getRequired(sessionId, this::deleteQueueSessionByCoreId);
	}

	/**
	 * Gets a list of sessions from core and deletes the local session data if a core session does not exist.
	 *
	 * @param  sessionIds The ids of the sessions
	 * @return            The session details
	 */
	public List<SessionDetailsDTO> getCoreSessions(List<Long> sessionIds) {
		return sessionCacheManager.getAndHandle(sessionIds, this::deleteQueueSessionByCoreId);
	}

	/**
	 * Deletes session if it exists.
	 *
	 * @param sessionId The session ID to delete.
	 */
	@Transactional
	public void deleteQueueSessionByCoreId(Long sessionId) {
		queueSessionRepository.deleteAllBySession(sessionId);
	}

	/**
	 * Create a copy of the {@param qSession} and convert it to {@link QueueSessionCreateDTO} so that users
	 * can copy and modify an exisiting session.
	 *
	 * @param  qSession The session to be copied
	 * @return          A QueueSessionCreateDTO object for the user.
	 */
	public QueueSessionCreateDTO<?> copyLabCreateDTO(QueueSession<?> qSession) {
		SessionDetailsDTO session = getCoreSession(qSession.getSession());
		return qSession.copyLabCreateDTO(session);
	}
}
