package org.fuseri.modulelanguageschool.lecture;


import org.fuseri.model.dto.course.LanguageTypeDto;
import org.fuseri.model.dto.course.ProficiencyLevelDto;
import org.fuseri.model.dto.lecture.LectureCreateDto;
import org.fuseri.model.dto.lecture.LectureDto;
import org.fuseri.model.dto.user.UserDto;
import org.fuseri.modulelanguageschool.course.CourseService;
import org.fuseri.modulelanguageschool.course.Language;
import org.fuseri.modulelanguageschool.course.ProficiencyLevel;
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 java.time.LocalDateTime;
import java.util.Collections;
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 LectureFacadeTest {

    private final UserDto USER = new UserDto("novakovat",
            "novakova@gamil.com", "Tereza", "Nováková",new HashMap<>());
    private final LectureCreateDto lectureCreateDto = new LectureCreateDto(
            LocalDateTime.now().plusDays(2),
            LocalDateTime.now().plusDays(2).plusHours(2),
            "Learning how to spell deprecated",
            10, 0L);
    private final LectureDto lectureDto = new LectureDto(
            LocalDateTime.now().plusDays(2),
            LocalDateTime.now().plusDays(2).plusHours(2),
            "Learning how to spell deprecated",
            10, 0L, 0L, Collections.emptyList());
    private final Lecture lecture = new Lecture();
    private final User user = new User();
    private final List<Lecture> lectureList = List.of(lecture);
    private final List<LectureDto> lectureDtoList = List.of(lectureDto);
    private final LanguageTypeDto languageTypeDto = LanguageTypeDto.ENGLISH;
    private final ProficiencyLevelDto proficiencyLevelDto = ProficiencyLevelDto.B1;


    @Autowired
    private LectureFacade lectureFacade;

    @MockBean
    private LectureService lectureService;

    @MockBean
    private LectureMapper lectureMapper;

    @MockBean
    private UserMapper userMapper;

    @MockBean
    private UserService userService;

    @Autowired
    private CourseService courseService;

    @Test
    void create() {
        when(lectureMapper.mapToLecture(lectureCreateDto, courseService)).thenReturn(lecture);
        when(lectureService.save(lecture)).thenReturn(lecture);
        when(lectureMapper.mapToDto(lecture)).thenReturn(lectureDto);

        LectureDto actualDto = lectureFacade.create(lectureCreateDto);

        assertEquals(lectureDto, actualDto);
    }

    @Test
    void testFindById() {
        Long id = 0L;
        when(lectureService.findById(id)).thenReturn(lecture);
        when(lectureMapper.mapToDto(lecture)).thenReturn(lectureDto);

        LectureDto actualDto = lectureFacade.findById(id);

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

    @Test
    void testFindAll() {
        var id = 1L;
        when(lectureService.findAllByCourse(anyLong())).thenReturn(lectureList);
        when(lectureMapper.mapToList(lectureList)).thenReturn(lectureDtoList);

        List<LectureDto> actualPageDtos = lectureFacade.findAll(id);

        assertEquals(lectureDtoList, actualPageDtos);
    }

    @Test
    void update() {
        Long id = 1L;
        when(lectureMapper.mapToLecture(lectureCreateDto, courseService)).thenReturn(lecture);
        when(lectureService.update(id, lecture)).thenReturn(lecture);
        when(lectureMapper.mapToDto(lecture)).thenReturn(lectureDto);

        LectureDto actualDto = lectureFacade.update(id, lectureCreateDto);

        assertEquals(lectureDto, actualDto);
    }

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

    @Test
    void testFindAllByLanguage() {
        when(lectureService.findAll(any(Language.class))).thenReturn(lectureList);
        when(lectureMapper.mapToList(lectureList)).thenReturn(lectureDtoList);

        List<LectureDto> actualDtoList = lectureFacade.findAll(languageTypeDto);

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

    @Test
    void testFindAllByLanguageAndProf() {
        when(lectureService.findAll(any(Language.class), any(ProficiencyLevel.class))).thenReturn(lectureList);
        when(lectureMapper.mapToList(lectureList)).thenReturn(lectureDtoList);

        List<LectureDto> actualDtoList = lectureFacade.findAll(languageTypeDto, proficiencyLevelDto);

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

    @Test
    void testEnrol() {
        Long id = 0L;
        when(lectureMapper.mapToDto(lecture)).thenReturn(lectureDto);
        when(userService.find(0L)).thenReturn(user);
        when(lectureService.enrol(anyLong(), any(User.class))).thenReturn(lecture);

        LectureDto actualDto = lectureFacade.enrol(id, 0L);

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

    @Test
    void testExpel() {
        Long id = 0L;
        when(lectureMapper.mapToDto(lecture)).thenReturn(lectureDto);
        when(userService.find(1L)).thenReturn(user);
        when(lectureService.expel(anyLong(), any(User.class))).thenReturn(lecture);

        LectureDto actualDto = lectureFacade.expel(id, 1L);

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

    @Test
    void testSetLecturer() {
        Long id = 0L;
        when(lectureMapper.mapToDto(lecture)).thenReturn(lectureDto);
        when(userService.find(1L)).thenReturn(user);
        when(lectureService.setLecturer(anyLong(), any(User.class))).thenReturn(lecture);

        LectureDto actualDto = lectureFacade.setLecturer(id, 1L);

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

