package org.fuseri.moduleexercise.exercise;

import jakarta.persistence.EntityNotFoundException;
import org.fuseri.model.dto.exercise.ExerciseCreateDto;
import org.fuseri.moduleexercise.question.Question;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.test.mock.mockito.MockBean;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageImpl;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;

import java.util.Collections;
import java.util.HashSet;
import java.util.Optional;

import static org.mockito.ArgumentMatchers.anyLong;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;


@SpringBootTest
class ExerciseServiceTest {

    @MockBean
    ExerciseRepository exerciseRepository;

    @Autowired
    ExerciseService exerciseService;

    Exercise exercise;
    ExerciseCreateDto exercise2;
    ExerciseCreateDto exercise3;

    @BeforeEach
    void setup() {
        exercise = new Exercise("idioms", "exercise on basic idioms", 2, 1L, new HashSet<>());
        exercise2 = new ExerciseCreateDto("idioms1", "exercise on intermediate idioms", 2, 0);
        exercise3 = new ExerciseCreateDto("idioms2", "exercise on basic idioms", 1, 0L);
    }

    @Test
    void create() {
        when(exerciseRepository.save(exercise)).thenReturn(exercise);
        Exercise result = exerciseService.create(exercise);
        Assertions.assertEquals(exercise, result);
        verify(exerciseRepository).save(exercise);
    }

    @Test
    void notFound() {
        when(exerciseRepository.findById(anyLong())).thenReturn(Optional.empty());

        Assertions.assertThrows(EntityNotFoundException.class, () -> exerciseService.find(anyLong()));
    }

    @Test
    void find() {
        when(exerciseRepository.findById(anyLong())).thenReturn(Optional.of(exercise));

        Exercise result = exerciseService.find(anyLong());

        Assertions.assertEquals(exercise, result);
        verify(exerciseRepository).findById(anyLong());
    }

    @Test
    void findAll() {
        Pageable pageable = PageRequest.of(0, 10);
        Page<Exercise> page = new PageImpl<>(Collections.emptyList(), pageable, 0);

        when(exerciseRepository.findAll(pageable)).thenReturn(page);
        Page<Exercise> result = exerciseService.findAll(0);

        Assertions.assertEquals(page, result);
        verify(exerciseRepository).findAll(pageable);
    }

    @Test
    void findByCourseIdAndDifficulty() {
        PageRequest pageable = PageRequest.of(0, 10);
        Page<Exercise> page = new PageImpl<>(Collections.emptyList(), pageable, 0);

        when(exerciseRepository.findByCourseIdAndDifficulty(1L, 2, pageable)).thenReturn(page);

        Page<Exercise> result = exerciseService.findByCourseIdAndDifficulty(1L, 2, 0);

        Assertions.assertEquals(page, result);
        verify(exerciseRepository).findByCourseIdAndDifficulty(1L, 2, pageable);
    }


    @Test
    void getQuestions() {
        PageRequest pageable = PageRequest.of(0, 10);
        Page<Question> page = new PageImpl<>(Collections.emptyList(), pageable, 0);

        when(exerciseRepository.getQuestions(pageable, 1L)).thenReturn(page);
        when(exerciseRepository.existsById(1L)).thenReturn(true);


        Page<Question> result = exerciseService.getQuestions(1L, 0);

        Assertions.assertEquals(page, result);
        verify(exerciseRepository).getQuestions(pageable, 1L);
    }
}
