package com.ufund.api.ufundapi.service;

import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
import static org.junit.jupiter.api.Assertions.assertThrows;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;

import java.io.IOException;

import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;

import com.ufund.api.ufundapi.DuplicateKeyException;
import com.ufund.api.ufundapi.model.User;
import com.ufund.api.ufundapi.model.UserAuth;
import com.ufund.api.ufundapi.persistence.UserAuthDAO;

public class AuthServiceTest {

    private UserAuthDAO mockAuthDAO;
    private UserService mockUserService;
    private AuthService authService;

    @BeforeEach
    public void setupAuthService() {
        mockAuthDAO = mock(UserAuthDAO.class);
        mockUserService = mock(UserService.class);
        authService = new AuthService(mockAuthDAO, mockUserService);

    }

    @Test
    public void testAuthenticate() throws IOException {
        // Setup
        String username = "Fish";
        String key = UserAuth.generate(username).getKey();

        // Mock
        when(mockAuthDAO.getUserAuth(key)).thenReturn(new UserAuth(key, username, null));

        // Analyze
        assertDoesNotThrow(() -> authService.authenticate(username, key));

    }

    @Test
    public void testAuthenticateMismatchName() throws IOException {
        // Setup
        String username = "Fish";
        String key = UserAuth.generate(username).getKey();

        // Mock
        when(mockAuthDAO.getUserAuth(key)).thenReturn(new UserAuth(key, "EvilFish", null));

        // Analyze
        assertThrows(IllegalAccessException.class, () -> authService.authenticate(username, key));

    }

    @Test
    public void testAuthenticateMissingUserAuth() throws IOException {
        // Setup
        String username = "Fish";
        String key = UserAuth.generate(username).getKey();

        // Mock
        when(mockAuthDAO.getUserAuth(key)).thenReturn(null);

        // Analyze
        assertThrows(IllegalAccessException.class, () -> authService.authenticate(username, key));
        
    }

    @Test
    public void testLogin() throws IOException, DuplicateKeyException, IllegalAccessException {
        // Setup
        String username = "Fish";
        String password = "Chips";
        User user = User.create(username, password);

        // Mock
        when(mockUserService.getUser(username)).thenReturn(user);
                

        // Analyze
        assertDoesNotThrow(() -> authService.login(username, password));
    }

    @Test
    public void testLoginNullUser() throws IOException, DuplicateKeyException, IllegalAccessException {
        // Setup
        String username = "Fish";
        String password = "Chips";
        User user = User.create(username, password);

        // Mock
        when(mockUserService.getUser(username)).thenReturn(null);

        // Analyze
        assertThrows(IllegalAccessException.class, () -> authService.login(username, password));
    }

    @Test
    public void testLoginMismatchPasswords() throws IOException, DuplicateKeyException, IllegalAccessException {
        // Setup
        String username = "Fish";
        String password = "Chips";
        User user = User.create(username, password);

        // Mock
        when(mockUserService.getUser(username)).thenReturn(User.create(username, "fries"));

        // Analyze
        assertThrows(IllegalAccessException.class, () -> authService.login(username, password));
    }

    @Test
    public void testLogout() throws IOException, DuplicateKeyException, IllegalAccessException {
        // Setup
        String username = "Fish";
        String password = "Chips";
        String key = UserAuth.generate(username).getKey();
        User user = User.create(username, password);

        // Analyze
        assertDoesNotThrow(() -> authService.logout(key));
        
    }
    
}