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

import java.util.Optional;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.*;

import jakarta.transaction.Transactional;
import nl.tudelft.labracore.lib.security.user.AuthenticatedPerson;
import nl.tudelft.labracore.lib.security.user.Person;
import nl.tudelft.librador.resolver.annotations.PathEntity;
import nl.tudelft.queue.dto.patch.TimeSlotPatchDTO;
import nl.tudelft.queue.model.ClosableTimeSlot;
import nl.tudelft.queue.model.LabRequest;
import nl.tudelft.queue.model.TimeSlot;
import nl.tudelft.queue.service.RequestService;
import nl.tudelft.queue.service.TimeSlotService;

@Controller
public class TimeSlotController {

	@Autowired
	private RequestService rs;

	@Autowired
	private TimeSlotService tss;

	/**
	 * API endpoint for updating timeslots.
	 *
	 * @param id    The id of the timeslot to update.
	 * @param patch The updated timeslot data.
	 */
	@PatchMapping("/time-slot/{timeSlot}")
	@PreAuthorize("@permissionService.canManageTimeSlot(#timeSlot)")
	public @ResponseBody void patchTimeSlot(@PathEntity TimeSlot timeSlot,
			@RequestBody TimeSlotPatchDTO patch) {
		tss.patchTimeSlot(timeSlot, patch);
	}

	/**
	 * API endpoint for removing timeslots.
	 *
	 * @param id The id of the timeslot to remove.
	 */
	@DeleteMapping("/time-slot/{timeSlot}")
	@PreAuthorize("@permissionService.canManageTimeSlot(#timeSlot)")
	public @ResponseBody void deleteTimeSlot(@PathEntity TimeSlot timeSlot) {
		tss.deleteTimeSlot(timeSlot);
	}

	/**
	 * Closes the given time slot in the given lab if not yet closed. This means no more requests can be
	 * picked from that time slot other than the requests currently picked from there.
	 *
	 * @param  timeSlot The time slot to close.
	 * @return          A redirect to the lab overview page.
	 */
	@Transactional
	@GetMapping("/time-slot/{timeSlot}/close")
	@PreAuthorize("@permissionService.canCloseTimeSlot(#timeSlot)")
	public String closeTimeSlot(@PathEntity ClosableTimeSlot timeSlot) {
		tss.closeTimeSlot(timeSlot);
		return "redirect:/lab/" + timeSlot.getLab().getId();
	}

	/**
	 * Takes a next request for the currently authenticated person in the given time slot. The person will get
	 * assigned a random request based on the
	 * {@link RequestService#takeNextRequestFromTimeSlot(Person, ClosableTimeSlot)} method.
	 *
	 * @param  person   The currently authenticated person getting the next request.
	 * @param  timeSlot The time slot for which the person wants a next request.
	 * @return          A redirect to the request page or the lab page if no request was picked.
	 */
	@Transactional
	@GetMapping("/time-slot/{timeSlot}/take-next")
	@PreAuthorize("@permissionService.canTakeFromTimeSlot(#timeSlot)")
	public String takeNextFromTimeSlot(@AuthenticatedPerson Person person,
			@PathEntity ClosableTimeSlot timeSlot) {
		Optional<LabRequest> request = rs.takeNextRequestFromTimeSlot(person, timeSlot);

		return request.map(r -> "redirect:/request/" + r.getId())
				.orElse("redirect:/lab/" + timeSlot.getLab().getId());
	}

}
