package org.fuseri.modulelanguageschool.course;


import org.fuseri.model.dto.course.CourseCreateDto;
import org.fuseri.model.dto.course.CourseDto;
import org.fuseri.model.dto.course.LanguageTypeDto;
import org.fuseri.model.dto.course.ProficiencyLevelDto;
import org.fuseri.model.dto.user.UserDto;
import org.fuseri.modulelanguageschool.user.User;
import org.fuseri.modulelanguageschool.user.UserMapper;
import org.fuseri.modulelanguageschool.user.UserService;
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.HashMap;
import java.util.List;

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


@SpringBootTest
@AutoConfigureMockMvc
final class CourseFacadeTest {

    private final UserDto USER = new UserDto("novakovat",
            "novakova@gamil.com", "Tereza", "Nováková",new HashMap<>());
    private final CourseDto courseDto = new CourseDto("AJ1", 10,
            LanguageTypeDto.ENGLISH, ProficiencyLevelDto.A1);
    private final CourseCreateDto courseCreateDto = new CourseCreateDto("AJ1", 10,
            LanguageTypeDto.ENGLISH, ProficiencyLevelDto.A1);
    private final Course course = new Course();
    private final User user = new User();
    private final List<Course> courseList = List.of(course);
    private final List<CourseDto> courseDtoList = List.of(courseDto);
    private final LanguageTypeDto languageTypeDto = LanguageTypeDto.ENGLISH;
    private final ProficiencyLevelDto proficiencyLevelDto = ProficiencyLevelDto.B1;


    @Autowired
    private CourseFacade courseFacade;

    @MockBean
    private CourseService courseService;

    @MockBean
    private CourseMapper courseMapper;

    @MockBean
    private UserService userService;

    @Test
    void create() {
        when(courseMapper.mapToCourse(courseCreateDto)).thenReturn(course);
        when(courseService.save(course)).thenReturn(course);
        when(courseMapper.mapToDto(course)).thenReturn(courseDto);

        CourseDto actualDto = courseFacade.create(courseCreateDto);

        assertEquals(courseDto, actualDto);
    }

    @Test
    void testFindById() {
        Long id = 0L;
        when(courseService.findById(id)).thenReturn(course);
        when(courseMapper.mapToDto(course)).thenReturn(courseDto);

        CourseDto actualDto = courseFacade.findById(id);

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

    @Test
    void testFindAll() {
        Pageable pageable = PageRequest.of(0, 10);
        Page<Course> certificatePage = new PageImpl<>(List.of(course), pageable, 0);
        Page<CourseDto> expectedPageDto = new PageImpl<>(List.of(courseDto), pageable, 0);

        when(courseService.findAll(pageable)).thenReturn(certificatePage);
        when(courseMapper.mapToPageDto(certificatePage)).thenReturn(expectedPageDto);

        Page<CourseDto> actualPageDto = courseFacade.findAll(pageable);

        assertEquals(expectedPageDto, actualPageDto);
    }

    @Test
    void update() {
        Long id = 1L;
        when(courseMapper.mapToCourse(courseCreateDto)).thenReturn(course);
        when(courseService.update(id, course)).thenReturn(course);
        when(courseMapper.mapToDto(course)).thenReturn(courseDto);

        CourseDto actualDto = courseFacade.update(id, courseCreateDto);

        assertEquals(courseDto, actualDto);
    }

    @Test
    void testDelete() {
        Long id = 1L;
        courseFacade.delete(id);
        verify(courseService).delete(id);
    }

    @Test
    void testFindAllByLanguage() {
        when(courseService.findAll(any(Language.class))).thenReturn(courseList);
        when(courseMapper.mapToList(courseList)).thenReturn(courseDtoList);

        List<CourseDto> actualDtoList = courseFacade.findAll(languageTypeDto);

        assertNotNull(actualDtoList);
        assertEquals(courseDtoList, actualDtoList);
    }

    @Test
    void testFindAllByLanguageAndProf() {
        when(courseService.findAll(any(Language.class), any(ProficiencyLevel.class))).thenReturn(courseList);
        when(courseMapper.mapToList(courseList)).thenReturn(courseDtoList);

        List<CourseDto> actualDtoList = courseFacade.findAll(languageTypeDto, proficiencyLevelDto);

        assertNotNull(actualDtoList);
        assertEquals(courseDtoList, actualDtoList);
    }

    @Test
    void testExpel() {
        Long id = 0L;
        when(userService.find(anyLong())).thenReturn(user);
        when(courseMapper.mapToDto(course)).thenReturn(courseDto);
        when(courseService.expel(anyLong(), any(User.class))).thenReturn(course);

        CourseDto actualDto = courseFacade.expel(id, 1L);

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



}
