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

import dev.lions.faces.layout.view.UserSessionBean;
import dev.lions.user.manager.client.service.RealmAssignmentServiceClient;
import dev.lions.user.manager.client.service.RealmServiceClient;
import dev.lions.user.manager.client.service.UserServiceClient;
import dev.lions.user.manager.dto.realm.RealmAssignmentDTO;
import dev.lions.user.manager.dto.user.UserDTO;
import dev.lions.user.manager.dto.user.UserSearchResultDTO;
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 org.mockito.junit.jupiter.MockitoSettings;
import org.mockito.quality.Strictness;
import org.eclipse.microprofile.rest.client.inject.RestClient;

import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

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

/**
 * Tests unitaires pour RealmAssignmentBean
 */
@ExtendWith(MockitoExtension.class)
@MockitoSettings(strictness = Strictness.LENIENT)
class RealmAssignmentBeanTest {

    @Mock
    @RestClient
    private RealmAssignmentServiceClient realmAssignmentServiceClient;

    @Mock
    @RestClient
    private UserServiceClient userServiceClient;

    @Mock
    @RestClient
    private RealmServiceClient realmServiceClient;

    @Mock
    private UserSessionBean userSessionBean;

    @Mock
    private FacesContext facesContext;

    @InjectMocks
    private RealmAssignmentBean realmAssignmentBean;

    MockedStatic<FacesContext> facesContextMock;

    @BeforeEach
    void setUp() {
        // Mock FacesContext
        facesContextMock = mockStatic(FacesContext.class);
        facesContextMock.when(FacesContext::getCurrentInstance).thenReturn(facesContext);
        doNothing().when(facesContext).addMessage(isNull(), any(FacesMessage.class));
    }

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

    @Test
    void testInit_WithAdminRole() {
        when(userSessionBean.hasRole("admin")).thenReturn(true);
        when(realmAssignmentServiceClient.getAllAssignments()).thenReturn(Collections.emptyList());
        when(userServiceClient.getAllUsers(anyString(), anyInt(), anyInt()))
                .thenReturn(UserSearchResultDTO.builder().users(Collections.emptyList()).build());
        when(realmServiceClient.getAllRealms()).thenReturn(Collections.emptyList());

        realmAssignmentBean.init();

        verify(realmAssignmentServiceClient).getAllAssignments();
        verify(userServiceClient).getAllUsers(anyString(), anyInt(), anyInt());
        verify(realmServiceClient).getAllRealms();
    }

    @Test
    void testInit_WithoutAdminRole() {
        when(userSessionBean.hasRole("admin")).thenReturn(false);

        realmAssignmentBean.init();

        verify(realmAssignmentServiceClient, never()).getAllAssignments();
    }

    @Test
    void testLoadAssignments_Success() {
        List<RealmAssignmentDTO> assignments = new ArrayList<>();
        assignments.add(RealmAssignmentDTO.builder().id("1").build());
        when(realmAssignmentServiceClient.getAllAssignments()).thenReturn(assignments);

        realmAssignmentBean.loadAssignments();

        assertEquals(1, realmAssignmentBean.getAssignments().size());
        verify(realmAssignmentServiceClient).getAllAssignments();
    }

    @Test
    void testLoadAssignments_Error() {
        when(realmAssignmentServiceClient.getAllAssignments()).thenThrow(new RuntimeException("Error"));

        realmAssignmentBean.loadAssignments();

        assertTrue(realmAssignmentBean.getAssignments().isEmpty());
    }

    @Test
    void testLoadAvailableUsers_Success() {
        List<UserDTO> users = new ArrayList<>();
        users.add(UserDTO.builder().id("1").username("user1").build());
        UserSearchResultDTO result = UserSearchResultDTO.builder().users(users).build();
        when(userServiceClient.getAllUsers(anyString(), anyInt(), anyInt())).thenReturn(result);

        realmAssignmentBean.loadAvailableUsers();

        assertEquals(1, realmAssignmentBean.getAvailableUsers().size());
    }

    @Test
    void testLoadAvailableUsers_NullResult() {
        when(userServiceClient.getAllUsers(anyString(), anyInt(), anyInt())).thenReturn(null);

        realmAssignmentBean.loadAvailableUsers();

        assertTrue(realmAssignmentBean.getAvailableUsers().isEmpty());
    }

    @Test
    void testLoadAvailableRealms_Success() {
        List<String> realms = List.of("realm1", "realm2");
        when(realmServiceClient.getAllRealms()).thenReturn(realms);

        realmAssignmentBean.loadAvailableRealms();

        assertEquals(2, realmAssignmentBean.getAvailableRealms().size());
    }

    @Test
    void testLoadAvailableRealms_Empty() {
        when(realmServiceClient.getAllRealms()).thenReturn(Collections.emptyList());

        realmAssignmentBean.loadAvailableRealms();

        assertTrue(realmAssignmentBean.getAvailableRealms().isEmpty());
    }

    @Test
    void testAssignRealm_Success() {
        when(userSessionBean.hasRole("admin")).thenReturn(true);
        when(userSessionBean.getUsername()).thenReturn("admin");

        List<UserDTO> users = new ArrayList<>();
        UserDTO user = UserDTO.builder()
                .id("user1")
                .username("testuser")
                .email("test@example.com")
                .build();
        users.add(user);
        UserSearchResultDTO result = UserSearchResultDTO.builder().users(users).build();
        when(userServiceClient.getAllUsers(anyString(), anyInt(), anyInt())).thenReturn(result);

        realmAssignmentBean.setAvailableUsers(users);
        realmAssignmentBean.setSelectedUserId("user1");
        realmAssignmentBean.setSelectedRealmName("realm1");

        RealmAssignmentDTO created = RealmAssignmentDTO.builder().id("1").build();
        jakarta.ws.rs.core.Response response = mock(jakarta.ws.rs.core.Response.class);
        when(response.readEntity(RealmAssignmentDTO.class)).thenReturn(created);

        when(realmAssignmentServiceClient.assignRealmToUser(any(RealmAssignmentDTO.class)))
                .thenReturn(response);

        realmAssignmentBean.assignRealm();

        verify(realmAssignmentServiceClient).assignRealmToUser(any(RealmAssignmentDTO.class));
    }

    @Test
    void testAssignRealm_NoUserId() {
        realmAssignmentBean.setSelectedUserId(null);
        realmAssignmentBean.setSelectedRealmName("realm1");

        realmAssignmentBean.assignRealm();

        verify(realmAssignmentServiceClient, never()).assignRealmToUser(any());
    }

    @Test
    void testAssignRealm_NoRealmName() {
        realmAssignmentBean.setSelectedUserId("user1");
        realmAssignmentBean.setSelectedRealmName(null);

        realmAssignmentBean.assignRealm();

        verify(realmAssignmentServiceClient, never()).assignRealmToUser(any());
    }

    @Test
    void testRevokeAssignment_Success() {
        RealmAssignmentDTO assignment = RealmAssignmentDTO.builder()
                .id("1")
                .userId("user1")
                .username("testuser")
                .realmName("realm1")
                .build();
        when(realmAssignmentServiceClient.getAllAssignments()).thenReturn(Collections.emptyList());

        realmAssignmentBean.revokeAssignment(assignment);

        verify(realmAssignmentServiceClient).revokeRealmFromUser("user1", "realm1");
    }

    @Test
    void testRevokeAssignment_Null() {
        realmAssignmentBean.revokeAssignment(null);

        verify(realmAssignmentServiceClient, never()).revokeRealmFromUser(anyString(), anyString());
    }

    @Test
    void testDeactivateAssignment_Success() {
        RealmAssignmentDTO assignment = RealmAssignmentDTO.builder()
                .id("1")
                .build();
        when(realmAssignmentServiceClient.getAllAssignments()).thenReturn(Collections.emptyList());

        realmAssignmentBean.deactivateAssignment(assignment);

        verify(realmAssignmentServiceClient).deactivateAssignment("1");
    }

    @Test
    void testActivateAssignment_Success() {
        RealmAssignmentDTO assignment = RealmAssignmentDTO.builder()
                .id("1")
                .build();
        when(realmAssignmentServiceClient.getAllAssignments()).thenReturn(Collections.emptyList());

        realmAssignmentBean.activateAssignment(assignment);

        verify(realmAssignmentServiceClient).activateAssignment("1");
    }

    @Test
    void testSetSuperAdmin_Success() {
        List<UserDTO> users = new ArrayList<>();
        UserDTO user = UserDTO.builder()
                .id("user1")
                .username("testuser")
                .build();
        users.add(user);
        realmAssignmentBean.setAvailableUsers(users);
        when(realmAssignmentServiceClient.getAllAssignments()).thenReturn(Collections.emptyList());

        realmAssignmentBean.setSuperAdmin("user1", true);

        verify(realmAssignmentServiceClient).setSuperAdmin("user1", true);
    }

    @Test
    void testResetForm() {
        realmAssignmentBean.setSelectedUserId("user1");
        realmAssignmentBean.setSelectedRealmName("realm1");

        realmAssignmentBean.resetForm();

        assertNull(realmAssignmentBean.getSelectedUserId());
        assertNull(realmAssignmentBean.getSelectedRealmName());
    }

    @Test
    void testGetFilteredAssignments_NoFilters() {
        List<RealmAssignmentDTO> assignments = new ArrayList<>();
        assignments.add(RealmAssignmentDTO.builder().username("user1").realmName("realm1").build());
        realmAssignmentBean.setAssignments(assignments);
        realmAssignmentBean.setFilterUserName(null);
        realmAssignmentBean.setFilterRealmName(null);

        List<RealmAssignmentDTO> filtered = realmAssignmentBean.getFilteredAssignments();

        assertEquals(1, filtered.size());
    }

    @Test
    void testGetFilteredAssignments_WithFilters() {
        List<RealmAssignmentDTO> assignments = new ArrayList<>();
        assignments.add(RealmAssignmentDTO.builder().username("user1").realmName("realm1").build());
        assignments.add(RealmAssignmentDTO.builder().username("user2").realmName("realm2").build());
        realmAssignmentBean.setAssignments(assignments);
        realmAssignmentBean.setFilterUserName("user1");
        realmAssignmentBean.setFilterRealmName("realm1");

        List<RealmAssignmentDTO> filtered = realmAssignmentBean.getFilteredAssignments();

        assertEquals(1, filtered.size());
        assertEquals("user1", filtered.get(0).getUsername());
    }

    @Test
    void testGetTotalAssignments() {
        List<RealmAssignmentDTO> assignments = new ArrayList<>();
        assignments.add(RealmAssignmentDTO.builder().build());
        assignments.add(RealmAssignmentDTO.builder().build());
        realmAssignmentBean.setAssignments(assignments);

        assertEquals(2, realmAssignmentBean.getTotalAssignments());
    }

    @Test
    void testGetActiveAssignmentsCount() {
        List<RealmAssignmentDTO> assignments = new ArrayList<>();
        assignments.add(RealmAssignmentDTO.builder().active(true).build());
        assignments.add(RealmAssignmentDTO.builder().active(false).build());
        assignments.add(RealmAssignmentDTO.builder().active(true).build());
        realmAssignmentBean.setAssignments(assignments);

        assertEquals(2, realmAssignmentBean.getActiveAssignmentsCount());
    }

    @Test
    void testGetSuperAdminsCount() {
        List<RealmAssignmentDTO> assignments = new ArrayList<>();
        assignments.add(RealmAssignmentDTO.builder().isSuperAdmin(true).build());
        assignments.add(RealmAssignmentDTO.builder().isSuperAdmin(false).build());
        assignments.add(RealmAssignmentDTO.builder().isSuperAdmin(true).build());
        realmAssignmentBean.setAssignments(assignments);

        assertEquals(2, realmAssignmentBean.getSuperAdminsCount());
    }
}
