package com.plannaplan.services;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringRunner;

import static org.junit.jupiter.api.Assertions.assertTrue;

import java.util.List;

import com.plannaplan.entities.User;
import com.plannaplan.exceptions.UserNotFoundException;
import com.plannaplan.types.UserRoles;

import org.junit.Test;
import org.junit.jupiter.api.TestMethodOrder;
import org.junit.jupiter.api.MethodOrderer.OrderAnnotation;
import org.junit.runner.RunWith;

@RunWith(SpringRunner.class)
@SpringBootTest
@ContextConfiguration
@TestMethodOrder(OrderAnnotation.class)
public class UserServiceTest {
    private static String TEST_USER_MAIL = "noteexisitingmail@notexistingdomain.com";
    private static String TEST_USER_NAME = "Tom";
    private static String TEST_USER_SUERNAME = "Kovalsky";

    @Autowired
    private UserService userService;

    @Test
    public void shouldReturnToken() {
        final User testUser = new User(TEST_USER_NAME, TEST_USER_SUERNAME, TEST_USER_MAIL, UserRoles.TEST_USER);
        this.userService.save(testUser);
        try {
            final String token = this.userService.login(TEST_USER_MAIL);
            System.out.println("Returned token: " + token);
            assertTrue(token != null);
            assertTrue(this.userService.getUserByEmail(TEST_USER_MAIL).getToken() != null);
        } catch (UserNotFoundException e) {
            e.printStackTrace();
            assertTrue(false);
        }
    }

    @Test
    public void shouldThrowException() {
        try {
            this.userService.login("thiseamilisnotindatabase@gmail.com");
            assertTrue(false);
        } catch (UserNotFoundException e) {
            assertTrue(true);
        }
    }

    @Test
    public void shouldFindStudents() {
        this.userService.save(new User("Nemo", "TheFish", "Nemo@shouldFindStudents.test", UserRoles.STUDENT));
        final List<User> response = this.userService.searchForStudents("Nemo");
        assertTrue(response.size() >= 1);
        assertTrue(containsName(response, "Nemo"));
    }

    @Test
    public void shouldReturnAllStudents() {
        final User veryWantedUser = new User("Xavier", "123", "Xavier@shouldReturnAllStudents.test", UserRoles.STUDENT);
        final User littleLessWanted = new User("Ravier", "321", "Ravier@shouldReturnAllStudents.test",
                UserRoles.STUDENT);
        final User notWantadUser = new User("Fiona", "Raskolnikov", "Fiona@shouldReturnAllStudents.test",
                UserRoles.DEANERY);

        this.userService.save(veryWantedUser);
        this.userService.save(littleLessWanted);
        this.userService.save(notWantadUser);

        final List<User> response = this.userService.searchForStudents("");
        assertTrue(response.size() >= 2);
        assertTrue(!containsName(response, notWantadUser.getName()));
        assertTrue(containsName(response, littleLessWanted.getName()));
        assertTrue(containsName(response, veryWantedUser.getName()));
    }

    @Test
    public void shouldntFindStudents() {
        this.userService.save(new User("Nadia", "Ladia", "Nadia@shouldntFindStudents.test", UserRoles.STUDENT));
        final List<User> response = this.userService.searchForStudents(
                "THISisIMPOIBLEQUEryThatShouldntReturnAnyPersonAtAllfnjiasdfjivlsdfnjgklsomerandomcharsjustinCaseXD");
        assertTrue(response.size() == 0);
    }

    private boolean containsName(final List<User> list, final String name) {
        return list.stream().map(User::getName).filter(name::equals).findFirst().isPresent();
    }
}