package org.fuseri.moduleexercise.exercise;

import jakarta.persistence.EntityNotFoundException;
import jakarta.transaction.Transactional;
import org.fuseri.model.dto.exercise.ExerciseCreateDto;
import org.fuseri.model.dto.exercise.ExerciseDto;
import org.fuseri.model.dto.exercise.QuestionDto;
import org.fuseri.moduleexercise.question.Question;
import org.fuseri.moduleexercise.question.QuestionMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.stereotype.Service;

/**
 * Represent facade for managing exercises
 * Provide simplified interface for manipulating with exercises
 */
@Service
@Transactional
public class ExerciseFacade {
    private final ExerciseService exerciseService;
    private final ExerciseMapper exerciseMapper;
    private final QuestionMapper questionMapper;

    /**
     * Constructor for AnswerFacade
     *
     * @param exerciseService the service responsible for handling answer-related logic
     * @param exerciseMapper  the mapper responsible for converting between DTOs and entities
     */
    @Autowired
    public ExerciseFacade(ExerciseService exerciseService, ExerciseMapper exerciseMapper, QuestionMapper questionMapper) {
        this.exerciseService = exerciseService;
        this.exerciseMapper = exerciseMapper;
        this.questionMapper = questionMapper;
    }

    /**
     * Create a new exercise
     *
     * @param exerciseDto dto with information from which exercise is created
     * @return a created exercise dto
     */
    public ExerciseDto create(ExerciseCreateDto exerciseDto) {
        Exercise exerciseToCreate = exerciseMapper.fromCreateDto(exerciseDto);
        Exercise createdExercise = exerciseService.create(exerciseToCreate);
        return exerciseMapper.toDto(createdExercise);
    }

    /**
     * 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
     */
    @org.springframework.transaction.annotation.Transactional(readOnly = true)
    public ExerciseDto find(long id) {
        return exerciseMapper.toDto(exerciseService.find(id));
    }

    /**
     * Retrieve a page of Exercise entities
     *
     * @param page the page number to retrieve (0-indexed)
     * @return paginated exerciseDTOs
     */
    @org.springframework.transaction.annotation.Transactional(readOnly = true)
    public Page<ExerciseDto> findAll(int page) {
        return exerciseMapper.toDtoPage(exerciseService.findAll(page));
    }

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

    /**
     * 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 paginated questionDTOs associated with the specified exercise ID
     */
    @org.springframework.transaction.annotation.Transactional(readOnly = true)
    public Page<QuestionDto> getQuestions(long exerciseId, int page) {
        Page<Question> questions = exerciseService.getQuestions(exerciseId, page);
        return questionMapper.toDtoPage(questions);
    }

    /**
     * Update exercise
     *
     * @param id  the ID of the exercise to update
     * @param dto the ExerciseCreateDto object containing information about the exercise to update
     * @return an ExerciseDto object representing the updated exercise
     */
    public ExerciseDto update(long id, ExerciseCreateDto dto) {
        Exercise exercise = exerciseMapper.fromCreateDto(dto);
        Exercise updatedExercise = exerciseService.update(id, exercise);
        return exerciseMapper.toDto(updatedExercise);
    }

    /**
     * Delete exercise
     *
     * @param id of exercise to delete
     */
    public void delete(long id) {
        exerciseService.delete(id);
    }

}
