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

import dev.lions.user.manager.client.service.RealmServiceClient;
import dev.lions.user.manager.client.service.UserServiceClient;
import dev.lions.user.manager.dto.user.UserDTO;
import dev.lions.user.manager.enums.user.StatutUser;
import jakarta.faces.application.FacesMessage;
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 static org.junit.jupiter.api.Assertions.*;
import static org.mockito.ArgumentMatchers.*;
import static org.mockito.Mockito.*;

@ExtendWith(MockitoExtension.class)
class UserCreationBeanTest {

    @Mock
    UserServiceClient userServiceClient;

    @Mock
    RealmServiceClient realmServiceClient;

    @Mock
    FacesContext facesContext;

    @InjectMocks
    UserCreationBean userCreationBean;

    MockedStatic<FacesContext> facesContextMock;

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

    @BeforeEach
    void setUp() {
        facesContextMock = mockStatic(FacesContext.class);
        facesContextMock.when(FacesContext::getCurrentInstance).thenReturn(facesContext);
        // lenient car seul testInit déclenche loadRealms() → getAllRealms.
        // Les autres tests ne font pas appel à l'init cycle, donc le stub n'est
        // pas consommé → Mockito strict throws UnnecessaryStubbing.
        lenient().when(realmServiceClient.getAllRealms()).thenReturn(java.util.List.of("master"));
    }

    @AfterEach
    void tearDown() {
        if (facesContextMock != null) {
            facesContextMock.close();
        }
    }

    @Test
    void testInit() {
        userCreationBean.setDefaultRealm("master");
        userCreationBean.init();

        assertNotNull(userCreationBean.getNewUser());
        assertTrue(Boolean.TRUE.equals(userCreationBean.getNewUser().getEnabled()));
        assertFalse(Boolean.TRUE.equals(userCreationBean.getNewUser().getEmailVerified()));
        assertEquals(StatutUser.ACTIF, userCreationBean.getNewUser().getStatut());
        assertEquals("master", userCreationBean.getRealmName());
    }

    @Test
    void testCreateUser() {
        UserDTO newUser = UserDTO.builder()
                .username("newuser")
                .email("newuser@example.com")
                .prenom("John")
                .nom("Doe")
                .build();
        UserDTO createdUser = UserDTO.builder()
                .id("user-123")
                .username("newuser")
                .email("newuser@example.com")
                .build();

        jakarta.ws.rs.core.Response response = mock(jakarta.ws.rs.core.Response.class);
        when(response.readEntity(UserDTO.class)).thenReturn(createdUser);

        when(userServiceClient.createUser(any(UserDTO.class), eq(REALM_NAME)))
                .thenReturn(response);
        doNothing().when(userServiceClient).resetPassword(eq("user-123"), eq(REALM_NAME),
                any(dev.lions.user.manager.dto.user.PasswordResetRequestDTO.class));

        userCreationBean.setNewUser(newUser);
        userCreationBean.setPassword("password123");
        userCreationBean.setPasswordConfirm("password123");
        userCreationBean.setRealmName(REALM_NAME);

        userCreationBean.createUser();

        verify(userServiceClient).createUser(any(UserDTO.class), eq(REALM_NAME));
        verify(userServiceClient).resetPassword(eq("user-123"), eq(REALM_NAME),
                any(dev.lions.user.manager.dto.user.PasswordResetRequestDTO.class));
        verify(facesContext).addMessage(isNull(), any(FacesMessage.class));
    }

    @Test
    void testCreateUserEmptyPassword() {
        userCreationBean.setPassword("");
        userCreationBean.setPasswordConfirm("");

        userCreationBean.createUser();

        verify(userServiceClient, never()).createUser(any(), anyString());
        verify(facesContext).addMessage(isNull(), any(FacesMessage.class));
    }

    @Test
    void testCreateUserPasswordMismatch() {
        userCreationBean.setPassword("password1");
        userCreationBean.setPasswordConfirm("password2");

        userCreationBean.createUser();

        verify(userServiceClient, never()).createUser(any(), anyString());
        verify(facesContext).addMessage(isNull(), any(FacesMessage.class));
    }

    @Test
    void testCreateUserPasswordTooShort() {
        userCreationBean.setPassword("short");
        userCreationBean.setPasswordConfirm("short");

        userCreationBean.createUser();

        verify(userServiceClient, never()).createUser(any(), anyString());
        verify(facesContext).addMessage(isNull(), any(FacesMessage.class));
    }

    @Test
    void testCreateUserError() {
        when(userServiceClient.createUser(any(UserDTO.class), eq(REALM_NAME)))
                .thenThrow(new RuntimeException("Error"));

        userCreationBean.setPassword("password123");
        userCreationBean.setPasswordConfirm("password123");
        userCreationBean.setRealmName(REALM_NAME);

        userCreationBean.createUser();

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

    @Test
    void testResetForm() {
        UserDTO user = UserDTO.builder()
                .username("testuser")
                .email("test@example.com")
                .build();
        userCreationBean.setNewUser(user);
        userCreationBean.setPassword("password123");
        userCreationBean.setPasswordConfirm("password123");

        userCreationBean.resetForm();

        assertNotNull(userCreationBean.getNewUser());
        assertNull(userCreationBean.getPassword());
        assertNull(userCreationBean.getPasswordConfirm());
        assertTrue(Boolean.TRUE.equals(userCreationBean.getNewUser().getEnabled()));
        assertFalse(Boolean.TRUE.equals(userCreationBean.getNewUser().getEmailVerified()));
        assertEquals(StatutUser.ACTIF, userCreationBean.getNewUser().getStatut());
    }

    @Test
    void testCancel() {
        jakarta.faces.context.ExternalContext externalContext =
                mock(jakarta.faces.context.ExternalContext.class);
        when(facesContext.getExternalContext()).thenReturn(externalContext);

        userCreationBean.cancel();

        assertNotNull(userCreationBean.getNewUser());
    }
}
