package org.fuseri.moduleexercise.exercise;

import jakarta.persistence.EntityNotFoundException;
import lombok.Getter;
import org.fuseri.moduleexercise.common.DomainService;
import org.fuseri.moduleexercise.question.Question;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

/**
 * Represent a service for managing Exercise entities
 */
@Service
public class ExerciseService extends DomainService<Exercise> {

    /**
     * The repository instance used by this service
     */
    @Getter
    private final ExerciseRepository repository;

    /**
     * Construct a new instance of ExerciseService with the specified repository
     *
     * @param repository the repository instance to be used by this service
     */
    @Autowired
    public ExerciseService(ExerciseRepository repository) {
        this.repository = repository;
    }

    /**
     * Retrieve the Exercise entity with the specified ID
     *
     * @param id the ID of the Exercise entity to retrieve
     * @return the Exercise entity with the specified ID
     * @throws EntityNotFoundException if no Exercise entity exists with the specified ID
     */
    @Transactional(readOnly = true)
    public Exercise find(long id) {
        return repository.findById(id)
                .orElseThrow(() -> new EntityNotFoundException("Exercise '" + id + "' not found."));
    }

    /**
     * Retrieve a page of Exercise entities
     *
     * @param page the page number to retrieve (0-indexed)
     * @return a page of Exercise entities
     */
    @Transactional(readOnly = true)
    public Page<Exercise> findAll(int page) {
        return repository.findAll(PageRequest.of(page, DEFAULT_PAGE_SIZE));
    }

    /**
     * Retrieve a page of exercises filtered by the specified course id and difficulty level
     *
     * @param courseId   the id of the course to filter by
     * @param difficulty the difficulty level to filter by
     * @param page       the page number to retrieve
     * @return paginated exercises filtered by the specified course ID and difficulty level
     */
    public Page<Exercise> findByCourseIdAndDifficulty(long courseId, int difficulty, int page) {
        return repository.findByCourseIdAndDifficulty(courseId, difficulty, PageRequest.of(page, DEFAULT_PAGE_SIZE));
    }

    /**
     * Retrieve a page of Question entities associated with the specified exercise ID
     *
     * @param exerciseId the ID of the exercise to retrieve questions for
     * @param page       the page number to retrieve (0-indexed)
     * @return a page of Question entities associated with the specified exercise ID
     */
    @Transactional(readOnly = true)
    public Page<Question> getQuestions(long exerciseId, int page) {
        if (!repository.existsById(exerciseId)) {
            throw new EntityNotFoundException("Exercise with ID " + exerciseId + "does not exist.");
        }
        return repository.getQuestions(
                PageRequest.of(page, DomainService.DEFAULT_PAGE_SIZE),
                exerciseId);
    }

}
