package org.fuseri.moduleexercise.exercise;

import org.fuseri.model.dto.exercise.ExerciseCreateDto;
import org.fuseri.model.dto.exercise.ExerciseDto;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc;
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.List;

import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertNotNull;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;

@SpringBootTest
@AutoConfigureMockMvc
class ExerciseFacadeTest {

    @Autowired
    ExerciseFacade exerciseFacade;

    @MockBean
    ExerciseService exerciseService;

    @MockBean
    ExerciseMapper exerciseMapper;

    private final ExerciseDto exerciseDto = new ExerciseDto();

    private final ExerciseCreateDto exerciseCreateDto = new ExerciseCreateDto("name", "desc", 2, 1);

    private final Exercise exercise = new Exercise();

    @Test
    void create() {
        when(exerciseMapper.fromCreateDto(exerciseCreateDto)).thenReturn(exercise);
        when(exerciseService.create(exercise)).thenReturn(exercise);
        when(exerciseMapper.toDto(exercise)).thenReturn(exerciseDto);

        ExerciseDto actualDto = exerciseFacade.create(exerciseCreateDto);

        assertEquals(exerciseDto, actualDto);
    }

    @Test
    void testFindById() {
        long id = 1L;

        when(exerciseService.find(id)).thenReturn(exercise);
        when(exerciseMapper.toDto(exercise)).thenReturn(exerciseDto);

        ExerciseDto actualDto = exerciseFacade.find(id);

        assertNotNull(actualDto);
        assertEquals(exerciseDto, actualDto);
    }

    @Test
    void testFindAll() {
        int page = 0;
        Pageable pageable = PageRequest.of(0, 10);
        Page<Exercise> exercisePage = new PageImpl<>(List.of(exercise), pageable, 0);
        Page<ExerciseDto> expectedPageDto = new PageImpl<>(List.of(exerciseDto));

        when(exerciseService.findAll(page)).thenReturn(exercisePage);
        when(exerciseMapper.toDtoPage(exercisePage)).thenReturn(expectedPageDto);

        Page<ExerciseDto> actualPageDto = exerciseFacade.findAll(page);

        assertEquals(expectedPageDto, actualPageDto);
    }

    @Test
    void update() {
        long id = 1L;
        when(exerciseMapper.fromCreateDto(exerciseCreateDto)).thenReturn(exercise);
        when(exerciseService.update(id, exercise)).thenReturn(exercise);
        when(exerciseMapper.toDto(exercise)).thenReturn(exerciseDto);

        ExerciseDto actualDto = exerciseFacade.update(id, exerciseCreateDto);

        assertEquals(exerciseDto, actualDto);
    }

    @Test
    void testDelete() {
        long id = 1L;
        exerciseFacade.delete(id);
        verify(exerciseService).delete(id);
    }

}
