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

import java.time.LocalDateTime;
import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors;
import java.util.stream.StreamSupport;

import nl.tudelft.queue.model.Feedback;
import nl.tudelft.queue.model.QFeedback;

import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageImpl;
import org.springframework.data.domain.Pageable;
import org.springframework.data.querydsl.QuerydslPredicateExecutor;
import org.springframework.data.repository.CrudRepository;
import org.springframework.lang.NonNull;

import com.querydsl.core.types.Predicate;

public interface FeedbackRepository
		extends CrudRepository<Feedback, Feedback.Id>, QuerydslPredicateExecutor<Feedback> {
	QFeedback qf = QFeedback.feedback1;

	@NonNull
	@Override
	List<Feedback> findAll(@NonNull Predicate predicate);

	/**
	 * @param  requestId   The id of the request to lookup feedback for.
	 * @param  assistantId The id of the assistant to lookup feedback for.
	 * @return             The feedback given to the given assistant on the given request if one exists or
	 *                     none if one cannot be found.
	 */
	default Optional<Feedback> findById(Long requestId, Long assistantId) {
		return findById(new Feedback.Id(requestId, assistantId));
	}

	/**
	 * @param  assistantId The id of the assistant to lookup feedback for.
	 * @return             All feedback objects submitted for the assistant with the given id.
	 */
	default List<Feedback> findAllByAssistant(Long assistantId) {
		return findAll(qf.id.assistantId.eq(assistantId));
	}

	/**
	 * @param  assistantId The id of the assistant to lookup feedback for.
	 * @return             All feedback objects submitted for the assistant with the given id.
	 */
	default List<Feedback> findAllWithRatingByAssistant(Long assistantId) {
		return findAll(qf.id.assistantId.eq(assistantId).and(qf.rating.isNotNull()));
	}

	/**
	 * @param  assistantId The assistant to find Feedback for.
	 * @return             The page of feedback for the given Assistant.
	 */
	default List<Feedback> findByAssistant(Long assistantId) {
		return findAll(qf.id.assistantId.eq(assistantId)
				.and(qf.feedback.isNotNull()).and(qf.feedback.isNotEmpty()));
	}

	/**
	 * Gets the feedback for an assistant, but leaves out too recent feedback.
	 *
	 * @param  assistantId The assistant to find Feedback for.
	 * @param  pageable    The pageable object to page feedback with.
	 * @return             The page of feedback for the given Assistant.
	 */
	default Page<Feedback> findByAssistantAnonymised(Long assistantId, Pageable pageable) {
		var feedback = StreamSupport.stream(findAll(qf.id.assistantId.eq(assistantId)
				.and(qf.createdAt.before(LocalDateTime.now().minusWeeks(2))), qf.createdAt.desc())
						.spliterator(),
				false)
				.skip(5)
				.filter(f -> f.getFeedback() != null && !f.getFeedback().isEmpty())
				.collect(Collectors.toList());
		var page = feedback.subList(pageable.getPageNumber() * pageable.getPageSize(),
				Math.min(feedback.size(), (pageable.getPageNumber() + 1) * pageable.getPageSize()));
		return new PageImpl<>(page, pageable, feedback.size());
	}
}
