package org.fuseri.moduleexercise.question;


import org.fuseri.model.dto.exercise.AnswerDto;
import org.fuseri.model.dto.exercise.AnswerInQuestionCreateDto;
import org.fuseri.model.dto.exercise.QuestionCreateDto;
import org.fuseri.model.dto.exercise.QuestionDto;
import org.fuseri.model.dto.exercise.QuestionUpdateDto;
import org.fuseri.moduleexercise.answer.Answer;
import org.fuseri.moduleexercise.answer.AnswerMapper;
import org.fuseri.moduleexercise.answer.AnswerService;
import org.fuseri.moduleexercise.exercise.Exercise;
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 java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

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
class QuestionFacadeTest {

    @Autowired
    QuestionFacade questionFacade;

    @MockBean
    QuestionService questionService;

    @MockBean
    AnswerService answerService;

    @MockBean
    QuestionMapper questionMapper;

    @MockBean
    AnswerMapper answerMapper;

    private final QuestionDto questionDto = new QuestionDto();

    private final QuestionCreateDto questionCreateDto = new QuestionCreateDto("name", 1L, new ArrayList<>());

    private final QuestionUpdateDto questionUpdateDto = QuestionUpdateDto.builder().build();

    private final Exercise exercise = new Exercise();

    private final Question question = new Question("text", new HashSet<>(), exercise);
    Set<Answer> answers = new HashSet<>(List.of(new Answer("BA", true, question)));

    @Test
    void create() {
        when(questionMapper.fromCreateDto(questionCreateDto)).thenReturn(question);
        when(questionService.create(question)).thenReturn(question);
        when(questionMapper.toDto(question)).thenReturn(questionDto);

        QuestionDto actualDto = questionFacade.create(questionCreateDto);

        assertEquals(questionDto, actualDto);
    }

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

        when(questionService.find(id)).thenReturn(question);
        when(questionMapper.toDto(question)).thenReturn(questionDto);

        QuestionDto actualDto = questionFacade.find(id);

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

    @Test
    void patchUpdate() {
        long id = 1L;
        when(questionMapper.fromUpdateDto(questionUpdateDto)).thenReturn(question);
        when(questionService.patchUpdateWithoutAnswers(id, question)).thenReturn(question);
        when(questionMapper.toDto(question)).thenReturn(questionDto);
        QuestionDto actualDto = questionFacade.patchUpdate(id, questionUpdateDto);

        assertEquals(questionDto, actualDto);
    }

    @Test
    void testDelete() {
        long id = 1L;
        when(questionService.find(id)).thenReturn(question);

        questionFacade.delete(id);
        verify(questionService).delete(id);
    }

    @Test
    void getQuestionAnswers() {
        long id = 1L;
        List<Answer> answers = List.of(new Answer("BA", true, question));
        question.setAnswers(new HashSet<>(answers));
        List<AnswerDto> answerDtos = List.of(new AnswerDto("BA", true));
        when(questionService.find(id)).thenReturn(question);
        when(answerMapper.toDtoList(answers)).thenReturn(answerDtos);
        var actualAnswers = questionFacade.getQuestionAnswers(id);
        assertEquals(answerDtos, actualAnswers);
    }

    @Test
    void addAnswers() {
        long id = 1L;
        question.setAnswers(answers);
        List<AnswerInQuestionCreateDto> answerDtos = List.of(new AnswerInQuestionCreateDto("BA", true));
        QuestionDto questionDtoAnswers = new QuestionDto(question.getText(), question.getExercise().getId(), List.of(new AnswerDto("BA", true)));

        when(answerMapper.fromCreateDtoList(answerDtos)).thenReturn(answers);
        when(questionService.addAnswers(id, answers)).thenReturn(question);
        when(questionMapper.toDto(question)).thenReturn(questionDtoAnswers);
        QuestionDto actualQuestionDto = questionFacade.addAnswers(id, answerDtos);
        assertEquals(questionDtoAnswers, actualQuestionDto);
    }
}
