package dev.lions.user.manager.client.view;

import dev.lions.user.manager.client.service.RestClientExceptionMapper;
import dev.lions.user.manager.client.service.UserServiceClient;
import dev.lions.user.manager.dto.user.UserDTO;
import jakarta.faces.application.FacesMessage;
import jakarta.faces.context.ExternalContext;
import jakarta.faces.context.FacesContext;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.MockedStatic;
import org.mockito.junit.jupiter.MockitoExtension;
import org.mockito.junit.jupiter.MockitoSettings;
import org.mockito.quality.Strictness;

import java.util.HashMap;
import java.util.Map;

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

@ExtendWith(MockitoExtension.class)
@MockitoSettings(strictness = Strictness.LENIENT)
class UserProfilBeanTest {

    @Mock
    UserServiceClient userServiceClient;

    @Mock
    RoleGestionBean roleGestionBean;

    @Mock
    FacesContext facesContext;

    @Mock
    ExternalContext externalContext;

    @InjectMocks
    UserProfilBean userProfilBean;

    MockedStatic<FacesContext> facesContextMock;

    private static final String USER_ID = "test-user-id";
    private static final String REALM_NAME = "lions-user-manager";

    @BeforeEach
    void setUp() {
        facesContextMock = mockStatic(FacesContext.class);
        facesContextMock.when(FacesContext::getCurrentInstance).thenReturn(facesContext);

        when(facesContext.getExternalContext()).thenReturn(externalContext);

        Map<String, String> params = new HashMap<>();
        params.put("userId", USER_ID);
        when(externalContext.getRequestParameterMap()).thenReturn(params);
    }

    @AfterEach
    void tearDown() {
        facesContextMock.close();
    }

    @Test
    void testInitWithUserId() {
        UserDTO user = UserDTO.builder()
                .id(USER_ID)
                .username("testuser")
                .build();
        when(userServiceClient.getUserById(USER_ID, REALM_NAME)).thenReturn(user);

        userProfilBean.init();

        assertNotNull(userProfilBean.getUser());
        assertEquals(USER_ID, userProfilBean.getUserId());
        assertEquals(REALM_NAME, userProfilBean.getRealmName());
        verify(roleGestionBean).setRealmName(REALM_NAME);
        verify(roleGestionBean).loadRealmRoles();
    }

    @Test
    void testInitWithoutUserId() {
        Map<String, String> emptyParams = new HashMap<>();
        when(externalContext.getRequestParameterMap()).thenReturn(emptyParams);

        userProfilBean.init();

        assertNull(userProfilBean.getUser());
        verify(facesContext).addMessage(isNull(), any(FacesMessage.class));
    }

    @Test
    void testLoadUser() {
        UserDTO user = UserDTO.builder()
                .id(USER_ID)
                .username("testuser")
                .build();
        when(userServiceClient.getUserById(USER_ID, REALM_NAME)).thenReturn(user);

        userProfilBean.setUserId(USER_ID);
        userProfilBean.setRealmName(REALM_NAME);
        userProfilBean.loadUser();

        assertNotNull(userProfilBean.getUser());
        assertEquals("testuser", userProfilBean.getUser().getUsername());
    }

    @Test
    void testLoadUserNotFound() {
        when(userServiceClient.getUserById(USER_ID, REALM_NAME))
                .thenThrow(new RestClientExceptionMapper.NotFoundException("User not found"));

        userProfilBean.setUserId(USER_ID);
        userProfilBean.setRealmName(REALM_NAME);
        userProfilBean.loadUser();

        assertNull(userProfilBean.getUser());
        verify(facesContext).addMessage(isNull(), any(FacesMessage.class));
    }

    @Test
    void testLoadUserError() {
        when(userServiceClient.getUserById(USER_ID, REALM_NAME))
                .thenThrow(new RuntimeException("Error"));

        userProfilBean.setUserId(USER_ID);
        userProfilBean.setRealmName(REALM_NAME);
        userProfilBean.loadUser();

        verify(facesContext).addMessage(isNull(), any(FacesMessage.class));
    }

    @Test
    void testEnableEditMode() {
        userProfilBean.enableEditMode();
        assertTrue(userProfilBean.isEditMode());
    }

    @Test
    void testCancelEdit() {
        UserDTO user = UserDTO.builder().id(USER_ID).username("testuser").build();
        when(userServiceClient.getUserById(USER_ID, REALM_NAME)).thenReturn(user);

        userProfilBean.setUserId(USER_ID);
        userProfilBean.setRealmName(REALM_NAME);
        userProfilBean.setEditMode(true);
        userProfilBean.cancelEdit();

        assertFalse(userProfilBean.isEditMode());
        verify(userServiceClient).getUserById(USER_ID, REALM_NAME);
    }

    @Test
    void testUpdateUser() {
        UserDTO user = UserDTO.builder()
                .id(USER_ID)
                .username("testuser")
                .email("test@example.com")
                .build();
        UserDTO updatedUser = UserDTO.builder()
                .id(USER_ID)
                .username("testuser")
                .email("updated@example.com")
                .build();

        when(userServiceClient.updateUser(eq(USER_ID), any(UserDTO.class), eq(REALM_NAME)))
                .thenReturn(updatedUser);

        userProfilBean.setUserId(USER_ID);
        userProfilBean.setRealmName(REALM_NAME);
        userProfilBean.setUser(user);
        userProfilBean.setEditMode(true);
        userProfilBean.updateUser();

        assertFalse(userProfilBean.isEditMode());
        verify(userServiceClient).updateUser(eq(USER_ID), any(UserDTO.class), eq(REALM_NAME));
        verify(facesContext).addMessage(isNull(), any(FacesMessage.class));
    }

    @Test
    void testUpdateUserError() {
        UserDTO user = UserDTO.builder().id(USER_ID).username("testuser").build();
        when(userServiceClient.updateUser(eq(USER_ID), any(UserDTO.class), eq(REALM_NAME)))
                .thenThrow(new RuntimeException("Error"));

        userProfilBean.setUserId(USER_ID);
        userProfilBean.setRealmName(REALM_NAME);
        userProfilBean.setUser(user);
        userProfilBean.updateUser();

        verify(facesContext).addMessage(isNull(), any(FacesMessage.class));
    }

    @Test
    void testResetPassword() {
        userProfilBean.setUserId(USER_ID);
        userProfilBean.setRealmName(REALM_NAME);
        userProfilBean.setNewPassword("newPassword123");
        userProfilBean.setNewPasswordConfirm("newPassword123");

        doNothing().when(userServiceClient).resetPassword(eq(USER_ID), eq(REALM_NAME),
                any(dev.lions.user.manager.dto.user.PasswordResetRequestDTO.class));

        userProfilBean.resetPassword();

        assertNull(userProfilBean.getNewPassword());
        assertNull(userProfilBean.getNewPasswordConfirm());
        verify(userServiceClient).resetPassword(eq(USER_ID), eq(REALM_NAME),
                any(dev.lions.user.manager.dto.user.PasswordResetRequestDTO.class));
        verify(facesContext).addMessage(isNull(), any(FacesMessage.class));
    }

    @Test
    void testResetPasswordEmpty() {
        userProfilBean.setNewPassword("");
        userProfilBean.resetPassword();

        verify(userServiceClient, never()).resetPassword(anyString(), anyString(),
                any(dev.lions.user.manager.dto.user.PasswordResetRequestDTO.class));
        verify(facesContext).addMessage(isNull(), any(FacesMessage.class));
    }

    @Test
    void testResetPasswordMismatch() {
        userProfilBean.setNewPassword("password1");
        userProfilBean.setNewPasswordConfirm("password2");
        userProfilBean.resetPassword();

        verify(userServiceClient, never()).resetPassword(anyString(), anyString(),
                any(dev.lions.user.manager.dto.user.PasswordResetRequestDTO.class));
        verify(facesContext).addMessage(isNull(), any(FacesMessage.class));
    }

    @Test
    void testResetPasswordError() {
        userProfilBean.setUserId(USER_ID);
        userProfilBean.setRealmName(REALM_NAME);
        userProfilBean.setNewPassword("newPassword123");
        userProfilBean.setNewPasswordConfirm("newPassword123");

        doThrow(new RuntimeException("Error"))
                .when(userServiceClient)
                .resetPassword(eq(USER_ID), eq(REALM_NAME),
                        any(dev.lions.user.manager.dto.user.PasswordResetRequestDTO.class));

        userProfilBean.resetPassword();

        verify(facesContext).addMessage(isNull(), any(FacesMessage.class));
    }

    @Test
    void testActivateUser() {
        UserDTO user = UserDTO.builder().id(USER_ID).username("testuser").build();
        when(userServiceClient.getUserById(USER_ID, REALM_NAME)).thenReturn(user);
        doNothing().when(userServiceClient).activateUser(USER_ID, REALM_NAME);

        userProfilBean.setUserId(USER_ID);
        userProfilBean.setRealmName(REALM_NAME);
        userProfilBean.activateUser();

        verify(userServiceClient).activateUser(USER_ID, REALM_NAME);
        verify(userServiceClient).getUserById(USER_ID, REALM_NAME);
        verify(facesContext).addMessage(isNull(), any(FacesMessage.class));
    }

    @Test
    void testActivateUserError() {
        doThrow(new RuntimeException("Error"))
                .when(userServiceClient).activateUser(USER_ID, REALM_NAME);

        userProfilBean.setUserId(USER_ID);
        userProfilBean.setRealmName(REALM_NAME);
        userProfilBean.activateUser();

        verify(facesContext).addMessage(isNull(), any(FacesMessage.class));
    }

    @Test
    void testDeactivateUser() {
        UserDTO user = UserDTO.builder().id(USER_ID).username("testuser").build();
        when(userServiceClient.getUserById(USER_ID, REALM_NAME)).thenReturn(user);
        doNothing().when(userServiceClient).deactivateUser(eq(USER_ID), eq(REALM_NAME), anyString());

        userProfilBean.setUserId(USER_ID);
        userProfilBean.setRealmName(REALM_NAME);
        userProfilBean.deactivateUser();

        verify(userServiceClient).deactivateUser(eq(USER_ID), eq(REALM_NAME), anyString());
        verify(userServiceClient).getUserById(USER_ID, REALM_NAME);
        verify(facesContext).addMessage(isNull(), any(FacesMessage.class));
    }

    @Test
    void testDeactivateUserError() {
        doThrow(new RuntimeException("Error"))
                .when(userServiceClient).deactivateUser(eq(USER_ID), eq(REALM_NAME), anyString());

        userProfilBean.setUserId(USER_ID);
        userProfilBean.setRealmName(REALM_NAME);
        userProfilBean.deactivateUser();

        verify(facesContext).addMessage(isNull(), any(FacesMessage.class));
    }

    @Test
    void testSendVerificationEmail() {
        doNothing().when(userServiceClient).sendVerificationEmail(USER_ID, REALM_NAME);

        userProfilBean.setUserId(USER_ID);
        userProfilBean.setRealmName(REALM_NAME);
        userProfilBean.sendVerificationEmail();

        verify(userServiceClient).sendVerificationEmail(USER_ID, REALM_NAME);
        verify(facesContext).addMessage(isNull(), any(FacesMessage.class));
    }

    @Test
    void testSendVerificationEmailError() {
        doThrow(new RuntimeException("Error"))
                .when(userServiceClient).sendVerificationEmail(USER_ID, REALM_NAME);

        userProfilBean.setUserId(USER_ID);
        userProfilBean.setRealmName(REALM_NAME);
        userProfilBean.sendVerificationEmail();

        verify(facesContext).addMessage(isNull(), any(FacesMessage.class));
    }

    @Test
    void testLogoutAllSessions() {
        doNothing().when(userServiceClient).logoutAllSessions(USER_ID, REALM_NAME);

        userProfilBean.setUserId(USER_ID);
        userProfilBean.setRealmName(REALM_NAME);
        userProfilBean.logoutAllSessions();

        verify(userServiceClient).logoutAllSessions(USER_ID, REALM_NAME);
        verify(facesContext).addMessage(isNull(), any(FacesMessage.class));
    }

    @Test
    void testLogoutAllSessionsError() {
        doThrow(new RuntimeException("Error"))
                .when(userServiceClient).logoutAllSessions(USER_ID, REALM_NAME);

        userProfilBean.setUserId(USER_ID);
        userProfilBean.setRealmName(REALM_NAME);
        userProfilBean.logoutAllSessions();

        verify(facesContext).addMessage(isNull(), any(FacesMessage.class));
    }
}
