package com.wishurgift.service;

import com.wishurgift.helper.CommentMaker;
import com.wishurgift.helper.ElementMaker;
import com.wishurgift.helper.UserMaker;
import com.wishurgift.helper.WishlistMaker;
import com.wishurgift.persistence.entity.Comment;
import com.wishurgift.persistence.entity.Element;
import com.wishurgift.persistence.entity.User;
import com.wishurgift.persistence.entity.Wishlist;
import com.wishurgift.persistence.repository.CommentRepository;
import com.wishurgift.persistence.repository.ElementRepository;
import com.wishurgift.persistence.repository.UserRepository;
import com.wishurgift.service.bean.CommentServiceBean;
import com.wishurgift.service.dto.CommentDTO;
import com.wishurgift.service.dto.UserDTO;
import com.wishurgift.service.dto.WishlistDTO;
import com.wishurgift.service.dto.request.CommentRequestDTO;
import com.wishurgift.service.dto.transformer.CommentTransformer;
import com.wishurgift.wrapper.Page;
import org.junit.Before;
import org.junit.Test;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.Mockito;
import org.mockito.MockitoAnnotations;

import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Optional;

import static org.junit.Assert.*;

public class CommentServiceTest {

    private static final SimpleDateFormat simpleDateFormat = new SimpleDateFormat("dd/MM/yyyy");

    @Mock
    CommentRepository commentRepository;

    @Mock
    WishlistService wishlistService;

    @Mock
    UserRepository userRepository;

    @Mock
    ElementRepository elementRepository;

    @InjectMocks
    CommentServiceBean service;

    @Before
    public void before() {
        MockitoAnnotations.initMocks(this);
    }

    @Test
    public void getByIdTest() {
        long id = 8;
        UserDTO userDTO = UserMaker.makeUserDTO();
        Comment expected = CommentMaker.makeComment();
        WishlistDTO wishlistDTO = WishlistMaker.makeWishlistDTO();

        Mockito.when(commentRepository.findById(id)).thenReturn(Optional.of(expected));
        Mockito.when(wishlistService.getWishlist(expected.getElement().getWishlist().getId(), userDTO)).thenReturn(wishlistDTO);

        CommentDTO actual = service.getById(userDTO, id);
        assertEquals(CommentTransformer.entityToDto(expected), actual);
    }

    @Test
    public void unauhtorizedGetByIdTest() {
        long id = 8;
        UserDTO userDTO = UserMaker.makeUserDTO();
        Comment expected = CommentMaker.makeComment();

        Mockito.when(commentRepository.findById(id)).thenReturn(Optional.of(expected));
        Mockito.when(wishlistService.getWishlist(expected.getElement().getWishlist().getId(), userDTO)).thenReturn(null);

        CommentDTO actual = service.getById(userDTO, id);
        assertNull(actual);
    }

    @Test
    public void notFoundGetByIdTest() {
        long id = 8;
        UserDTO userDTO = UserMaker.makeUserDTO();

        Mockito.when(commentRepository.findById(id)).thenReturn(Optional.empty());

        CommentDTO actual = service.getById(userDTO, id);
        assertNull(actual);
    }

    @Test
    public void putTest() {
        long id = 8;
        UserDTO userDTO = UserMaker.makeUserDTO();
        CommentRequestDTO request = CommentMaker.makeCommentRequestDTO();
        request.setText("newText");
        Comment comment = CommentMaker.makeComment();

        Mockito.when(commentRepository.findById(id)).thenReturn(Optional.of(comment));

        CommentDTO actual = service.put(userDTO, id, request);
        assertEquals(comment.getId(), actual.getId());
        assertEquals(request.getText(), actual.getText());
    }

    @Test
    public void notFoundPutTest() {
        long id = 8;
        UserDTO userDTO = UserMaker.makeUserDTO();
        CommentRequestDTO request = CommentMaker.makeCommentRequestDTO();

        Mockito.when(commentRepository.findById(id)).thenReturn(Optional.empty());

        CommentDTO actual = service.put(userDTO, id, request);
        assertNull(actual);
    }

    @Test
    public void unauthorizedPutTest() {
        long id = 8;
        UserDTO userDTO = UserMaker.makeUserDTO();
        userDTO.setId(2);
        CommentRequestDTO request = CommentMaker.makeCommentRequestDTO();
        request.setText("newText");
        Comment comment = CommentMaker.makeComment();

        Mockito.when(commentRepository.findById(id)).thenReturn(Optional.of(comment));

        CommentDTO actual = service.put(userDTO, id, request);
        assertNull(actual);
    }

    @Test
    public void deleteTest() {
        long id = 8;
        UserDTO userDTO = UserMaker.makeUserDTO();
        Comment comment = CommentMaker.makeComment();

        Mockito.when(commentRepository.findById(id)).thenReturn(Optional.of(comment));

        assertTrue(service.delete(userDTO, id));
    }

    @Test
    public void notFoundDeleteTest() {
        long id = 8;
        UserDTO userDTO = UserMaker.makeUserDTO();

        Mockito.when(commentRepository.findById(id)).thenReturn(Optional.empty());

        assertFalse(service.delete(userDTO, id));
    }

    @Test
    public void unauthorizedDeleteTest() {
        long id = 8;
        UserDTO userDTO = UserMaker.makeUserDTO();
        userDTO.setId(2);
        Comment comment = CommentMaker.makeComment();

        Mockito.when(commentRepository.findById(id)).thenReturn(Optional.of(comment));

        assertFalse(service.delete(userDTO, id));
    }

    @Test
    public void insertTest() {
        long id = 8;
        UserDTO userDTO = UserMaker.makeUserDTO();
        CommentRequestDTO request = CommentMaker.makeCommentRequestDTO();
        User user = UserMaker.makeUser();
        Element element = ElementMaker.makeElement();

        Mockito.when(userRepository.findById(userDTO.getId())).thenReturn(Optional.of(user));
        Mockito.when(elementRepository.findById(id)).thenReturn(Optional.of(element));

        CommentDTO actual = service.insert(userDTO, id, request);
        assertEquals(request.getText(), actual.getText());
        assertEquals(simpleDateFormat.format(new Date()), actual.getDate());
    }

    @Test
    public void userNotFoundInsertTest() {
        long id = 8;
        UserDTO userDTO = UserMaker.makeUserDTO();
        CommentRequestDTO request = CommentMaker.makeCommentRequestDTO();

        Mockito.when(userRepository.findById(userDTO.getId())).thenReturn(Optional.empty());

        CommentDTO actual = service.insert(userDTO, id, request);
        assertNull(actual);
    }

    @Test
    public void elementNotFoundInsertTest() {
        long id = 8;
        UserDTO userDTO = UserMaker.makeUserDTO();
        CommentRequestDTO request = CommentMaker.makeCommentRequestDTO();
        User user = UserMaker.makeUser();

        Mockito.when(userRepository.findById(userDTO.getId())).thenReturn(Optional.of(user));
        Mockito.when(elementRepository.findById(id)).thenReturn(Optional.empty());

        CommentDTO actual = service.insert(userDTO, id, request);
        assertNull(actual);
    }

    @Test
    public void getByElementTest() {
        long id = 8;
        UserDTO userDTO = UserMaker.makeUserDTO();
        Wishlist wishlist = WishlistMaker.makeWishlist();
        Element element = wishlist.getElements().get(0);
        WishlistDTO wishlistDTO = WishlistMaker.makeWishlistDTO();
        List<Comment> list = new ArrayList<>();
        list.add(CommentMaker.makeComment());
        list.add(CommentMaker.makeComment());
        list.get(1).setId(2);
        list.get(1).setText("otherText");

        Mockito.when(elementRepository.findById(id)).thenReturn(Optional.of(element));
        Mockito.when(wishlistService.getWishlist(wishlist.getId(), userDTO)).thenReturn(wishlistDTO);
        Mockito.when(commentRepository.getCommentByElement(element)).thenReturn(list);

        Page<CommentDTO> actual = service.getByElement(userDTO, id);
        assertNull(actual.getPage());
        assertNull(actual.getSize());
        assertEquals(list.size(), actual.getTotal());
        assertEquals(CommentTransformer.entityToDto(list), actual.getList());
    }

    @Test
    public void elementNotFoundGetByElementTest() {
        long id = 8;
        UserDTO userDTO = UserMaker.makeUserDTO();

        Mockito.when(elementRepository.findById(id)).thenReturn(Optional.empty());

        Page<CommentDTO> actual = service.getByElement(userDTO, id);
        assertNull(actual);
    }

    @Test
    public void unauthorizedGetByElementTest() {
        long id = 8;
        UserDTO userDTO = UserMaker.makeUserDTO();
        Wishlist wishlist = WishlistMaker.makeWishlist();
        Element element = wishlist.getElements().get(0);

        Mockito.when(elementRepository.findById(id)).thenReturn(Optional.of(element));
        Mockito.when(wishlistService.getWishlist(wishlist.getId(), userDTO)).thenReturn(null);

        Page<CommentDTO> actual = service.getByElement(userDTO, id);
        assertNull(actual);
    }

    @Test
    public void getByElementPageTest() {
        long id = 8;
        Integer page = 1;
        Integer size = 2;
        long total = 5;
        UserDTO userDTO = UserMaker.makeUserDTO();
        Wishlist wishlist = WishlistMaker.makeWishlist();
        Element element = wishlist.getElements().get(0);
        WishlistDTO wishlistDTO = WishlistMaker.makeWishlistDTO();
        List<Comment> list = new ArrayList<>();
        list.add(CommentMaker.makeComment());
        list.add(CommentMaker.makeComment());
        list.get(1).setId(2);
        list.get(1).setText("otherText");

        Mockito.when(elementRepository.findById(id)).thenReturn(Optional.of(element));
        Mockito.when(wishlistService.getWishlist(wishlist.getId(), userDTO)).thenReturn(wishlistDTO);
        Mockito.when(commentRepository.getCommentByElement(page, size, element)).thenReturn(list);
        Mockito.when(commentRepository.countCommentByElement(element)).thenReturn(total);

        Page<CommentDTO> actual = service.getByElement(userDTO, page, size, id);
        assertEquals(page, actual.getPage());
        assertEquals(size, actual.getSize());
        assertEquals(total, actual.getTotal());
        assertEquals(CommentTransformer.entityToDto(list), actual.getList());
    }

    @Test
    public void elementNotFoundGetByElementPageTest() {
        long id = 8;
        int page = 1;
        int size = 2;
        UserDTO userDTO = UserMaker.makeUserDTO();

        Mockito.when(elementRepository.findById(id)).thenReturn(Optional.empty());

        Page<CommentDTO> actual = service.getByElement(userDTO, page, size, id);
        assertNull(actual);
    }

    @Test
    public void unauthorizedGetByElementPageTest() {
        long id = 8;
        int page = 1;
        int size = 2;
        UserDTO userDTO = UserMaker.makeUserDTO();
        Wishlist wishlist = WishlistMaker.makeWishlist();
        Element element = wishlist.getElements().get(0);

        Mockito.when(elementRepository.findById(id)).thenReturn(Optional.of(element));
        Mockito.when(wishlistService.getWishlist(wishlist.getId(), userDTO)).thenReturn(null);

        Page<CommentDTO> actual = service.getByElement(userDTO, page, size, id);
        assertNull(actual);
    }

}
