package dev.lions.user.manager.resource;

import dev.lions.user.manager.dto.user.UserDTO;
import dev.lions.user.manager.dto.user.UserSearchCriteriaDTO;
import dev.lions.user.manager.dto.user.UserSearchResultDTO;
import dev.lions.user.manager.service.UserService;
import jakarta.ws.rs.core.Response;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.junit.jupiter.MockitoExtension;

import java.util.Collections;
import java.util.Optional;

import static org.junit.jupiter.api.Assertions.*;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.*;

@ExtendWith(MockitoExtension.class)
class UserResourceTest {

    @Mock
    UserService userService;

    @InjectMocks
    UserResource userResource;

    private static final String REALM = "test-realm";

    @Test
    void testSearchUsers() {
        UserSearchCriteriaDTO criteria = UserSearchCriteriaDTO.builder()
                .realmName(REALM)
                .searchTerm("test")
                .page(0)
                .pageSize(20)
                .build();

        UserSearchResultDTO mockResult = UserSearchResultDTO.builder()
                .users(Collections.singletonList(UserDTO.builder().username("test").build()))
                .totalCount(1L)
                .build();

        when(userService.searchUsers(any())).thenReturn(mockResult);

        Response response = userResource.searchUsers(criteria);

        assertEquals(200, response.getStatus());
        assertNotNull(response.getEntity());
    }

    @Test
    void testSearchUsersError() {
        UserSearchCriteriaDTO criteria = UserSearchCriteriaDTO.builder()
                .realmName(REALM)
                .build();

        when(userService.searchUsers(any())).thenThrow(new RuntimeException("Search failed"));

        Response response = userResource.searchUsers(criteria);

        assertEquals(500, response.getStatus());
    }

    @Test
    void testGetUserById() {
        UserDTO user = UserDTO.builder().id("1").username("testuser").build();
        when(userService.getUserById("1", REALM)).thenReturn(Optional.of(user));

        Response response = userResource.getUserById("1", REALM);

        assertEquals(200, response.getStatus());
        assertEquals(user, response.getEntity());
    }

    @Test
    void testGetUserByIdNotFound() {
        when(userService.getUserById("1", REALM)).thenReturn(Optional.empty());

        Response response = userResource.getUserById("1", REALM);

        assertEquals(404, response.getStatus());
    }

    @Test
    void testGetUserByIdError() {
        when(userService.getUserById("1", REALM)).thenThrow(new RuntimeException("Error"));

        Response response = userResource.getUserById("1", REALM);

        assertEquals(500, response.getStatus());
    }

    @Test
    void testGetAllUsers() {
        UserSearchResultDTO mockResult = UserSearchResultDTO.builder()
                .users(Collections.emptyList())
                .totalCount(0L)
                .build();
        when(userService.getAllUsers(REALM, 0, 20)).thenReturn(mockResult);

        Response response = userResource.getAllUsers(REALM, 0, 20);

        assertEquals(200, response.getStatus());
    }

    @Test
    void testGetAllUsersError() {
        when(userService.getAllUsers(REALM, 0, 20)).thenThrow(new RuntimeException("Error"));

        Response response = userResource.getAllUsers(REALM, 0, 20);

        assertEquals(500, response.getStatus());
    }

    @Test
    void testCreateUser() {
        UserDTO newUser = UserDTO.builder().username("newuser").email("new@test.com").build();
        UserDTO createdUser = UserDTO.builder().id("123").username("newuser").email("new@test.com").build();

        when(userService.createUser(any(), eq(REALM))).thenReturn(createdUser);

        Response response = userResource.createUser(newUser, REALM);

        assertEquals(201, response.getStatus());
        assertEquals(createdUser, response.getEntity());
    }

    @Test
    void testCreateUserError() {
        UserDTO newUser = UserDTO.builder().username("newuser").email("new@test.com").build();

        when(userService.createUser(any(), eq(REALM))).thenThrow(new RuntimeException("Create failed"));

        Response response = userResource.createUser(newUser, REALM);

        assertEquals(500, response.getStatus());
    }

    @Test
    void testUpdateUser() {
        UserDTO updateUser = UserDTO.builder()
                .username("updated")
                .prenom("John")
                .nom("Doe")
                .email("john.doe@test.com")
                .build();
        UserDTO updatedUser = UserDTO.builder()
                .id("1")
                .username("updated")
                .prenom("John")
                .nom("Doe")
                .email("john.doe@test.com")
                .build();

        when(userService.updateUser(eq("1"), any(), eq(REALM))).thenReturn(updatedUser);

        Response response = userResource.updateUser("1", updateUser, REALM);

        assertEquals(200, response.getStatus());
        assertEquals(updatedUser, response.getEntity());
    }

    @Test
    void testUpdateUserError() {
        UserDTO updateUser = UserDTO.builder()
                .username("updated")
                .prenom("John")
                .nom("Doe")
                .email("john.doe@test.com")
                .build();

        when(userService.updateUser(eq("1"), any(), eq(REALM))).thenThrow(new RuntimeException("Update failed"));

        Response response = userResource.updateUser("1", updateUser, REALM);

        assertEquals(500, response.getStatus());
    }

    @Test
    void testDeleteUser() {
        doNothing().when(userService).deleteUser("1", REALM, false);

        Response response = userResource.deleteUser("1", REALM, false);

        assertEquals(204, response.getStatus());
        verify(userService).deleteUser("1", REALM, false);
    }

    @Test
    void testDeleteUserHard() {
        doNothing().when(userService).deleteUser("1", REALM, true);

        Response response = userResource.deleteUser("1", REALM, true);

        assertEquals(204, response.getStatus());
        verify(userService).deleteUser("1", REALM, true);
    }

    @Test
    void testDeleteUserError() {
        doThrow(new RuntimeException("Delete failed")).when(userService).deleteUser("1", REALM, false);

        Response response = userResource.deleteUser("1", REALM, false);

        assertEquals(500, response.getStatus());
    }

    @Test
    void testActivateUser() {
        doNothing().when(userService).activateUser("1", REALM);

        Response response = userResource.activateUser("1", REALM);

        assertEquals(204, response.getStatus());
        verify(userService).activateUser("1", REALM);
    }

    @Test
    void testActivateUserError() {
        doThrow(new RuntimeException("Activate failed")).when(userService).activateUser("1", REALM);

        Response response = userResource.activateUser("1", REALM);

        assertEquals(500, response.getStatus());
    }

    @Test
    void testDeactivateUser() {
        doNothing().when(userService).deactivateUser("1", REALM, "reason");

        Response response = userResource.deactivateUser("1", REALM, "reason");

        assertEquals(204, response.getStatus());
        verify(userService).deactivateUser("1", REALM, "reason");
    }

    @Test
    void testDeactivateUserError() {
        doThrow(new RuntimeException("Deactivate failed")).when(userService).deactivateUser("1", REALM, null);

        Response response = userResource.deactivateUser("1", REALM, null);

        assertEquals(500, response.getStatus());
    }

    @Test
    void testResetPassword() {
        doNothing().when(userService).resetPassword("1", REALM, "newpassword", true);

        UserResource.PasswordResetRequest request = new UserResource.PasswordResetRequest();
        request.password = "newpassword";
        request.temporary = true;

        Response response = userResource.resetPassword("1", REALM, request);

        assertEquals(204, response.getStatus());
        verify(userService).resetPassword("1", REALM, "newpassword", true);
    }

    @Test
    void testResetPasswordError() {
        doThrow(new RuntimeException("Reset failed")).when(userService).resetPassword(any(), any(), any(),
                anyBoolean());

        UserResource.PasswordResetRequest request = new UserResource.PasswordResetRequest();
        request.password = "newpassword";

        Response response = userResource.resetPassword("1", REALM, request);

        assertEquals(500, response.getStatus());
    }

    @Test
    void testSendVerificationEmail() {
        doNothing().when(userService).sendVerificationEmail("1", REALM);

        Response response = userResource.sendVerificationEmail("1", REALM);

        assertEquals(204, response.getStatus());
        verify(userService).sendVerificationEmail("1", REALM);
    }

    @Test
    void testSendVerificationEmailError() {
        doThrow(new RuntimeException("Email failed")).when(userService).sendVerificationEmail("1", REALM);

        Response response = userResource.sendVerificationEmail("1", REALM);

        assertEquals(500, response.getStatus());
    }

    @Test
    void testLogoutAllSessions() {
        when(userService.logoutAllSessions("1", REALM)).thenReturn(5);

        Response response = userResource.logoutAllSessions("1", REALM);

        assertEquals(200, response.getStatus());
        assertNotNull(response.getEntity());
    }

    @Test
    void testLogoutAllSessionsError() {
        when(userService.logoutAllSessions("1", REALM)).thenThrow(new RuntimeException("Logout failed"));

        Response response = userResource.logoutAllSessions("1", REALM);

        assertEquals(500, response.getStatus());
    }

    @Test
    void testGetActiveSessions() {
        when(userService.getActiveSessions("1", REALM)).thenReturn(Collections.emptyList());

        Response response = userResource.getActiveSessions("1", REALM);

        assertEquals(200, response.getStatus());
    }

    @Test
    void testGetActiveSessionsError() {
        when(userService.getActiveSessions("1", REALM)).thenThrow(new RuntimeException("Sessions failed"));

        Response response = userResource.getActiveSessions("1", REALM);

        assertEquals(500, response.getStatus());
    }

    @Test
    void testPasswordResetRequestClass() {
        UserResource.PasswordResetRequest request = new UserResource.PasswordResetRequest();
        request.password = "password123";
        request.temporary = false;

        assertEquals("password123", request.password);
        assertFalse(request.temporary);
    }

    @Test
    void testSessionsRevokedResponseClass() {
        UserResource.SessionsRevokedResponse response = new UserResource.SessionsRevokedResponse(5);
        assertEquals(5, response.count);
    }

    @Test
    void testErrorResponseClass() {
        UserResource.ErrorResponse response = new UserResource.ErrorResponse("Error message");
        assertEquals("Error message", response.message);
    }
}
