package dev.lions.user.manager.resource;

import dev.lions.user.manager.dto.realm.RealmAssignmentDTO;
import dev.lions.user.manager.service.RealmAuthorizationService;
import jakarta.ws.rs.core.Response;
import jakarta.ws.rs.core.SecurityContext;
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.junit.jupiter.MockitoExtension;

import java.security.Principal;
import java.time.LocalDateTime;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.Optional;

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

/**
 * Tests unitaires pour RealmAssignmentResource
 */
@ExtendWith(MockitoExtension.class)
class RealmAssignmentResourceTest {

    @Mock
    private RealmAuthorizationService realmAuthorizationService;

    @Mock
    private SecurityContext securityContext;

    @Mock
    private Principal principal;

    @InjectMocks
    private RealmAssignmentResource realmAssignmentResource;

    private RealmAssignmentDTO assignment;

    @BeforeEach
    void setUp() {
        assignment = RealmAssignmentDTO.builder()
            .id("assignment-1")
            .userId("user-1")
            .username("testuser")
            .email("test@example.com")
            .realmName("realm1")
            .isSuperAdmin(false)
            .active(true)
            .assignedAt(LocalDateTime.now())
            .assignedBy("admin")
            .build();
    }

    @Test
    void testGetAllAssignments_Success() {
        List<RealmAssignmentDTO> assignments = Arrays.asList(assignment);
        when(realmAuthorizationService.getAllAssignments()).thenReturn(assignments);

        Response response = realmAssignmentResource.getAllAssignments();

        assertEquals(Response.Status.OK.getStatusCode(), response.getStatus());
        @SuppressWarnings("unchecked")
        List<RealmAssignmentDTO> responseAssignments = (List<RealmAssignmentDTO>) response.getEntity();
        assertEquals(1, responseAssignments.size());
    }

    @Test
    void testGetAllAssignments_Error() {
        when(realmAuthorizationService.getAllAssignments()).thenThrow(new RuntimeException("Error"));

        Response response = realmAssignmentResource.getAllAssignments();

        assertEquals(Response.Status.INTERNAL_SERVER_ERROR.getStatusCode(), response.getStatus());
    }

    @Test
    void testGetAssignmentsByUser_Success() {
        List<RealmAssignmentDTO> assignments = Arrays.asList(assignment);
        when(realmAuthorizationService.getAssignmentsByUser("user-1")).thenReturn(assignments);

        Response response = realmAssignmentResource.getAssignmentsByUser("user-1");

        assertEquals(Response.Status.OK.getStatusCode(), response.getStatus());
    }

    @Test
    void testGetAssignmentsByRealm_Success() {
        List<RealmAssignmentDTO> assignments = Arrays.asList(assignment);
        when(realmAuthorizationService.getAssignmentsByRealm("realm1")).thenReturn(assignments);

        Response response = realmAssignmentResource.getAssignmentsByRealm("realm1");

        assertEquals(Response.Status.OK.getStatusCode(), response.getStatus());
    }

    @Test
    void testGetAssignmentById_Success() {
        when(realmAuthorizationService.getAssignmentById("assignment-1")).thenReturn(Optional.of(assignment));

        Response response = realmAssignmentResource.getAssignmentById("assignment-1");

        assertEquals(Response.Status.OK.getStatusCode(), response.getStatus());
    }

    @Test
    void testGetAssignmentById_NotFound() {
        when(realmAuthorizationService.getAssignmentById("non-existent")).thenReturn(Optional.empty());

        Response response = realmAssignmentResource.getAssignmentById("non-existent");

        assertEquals(Response.Status.NOT_FOUND.getStatusCode(), response.getStatus());
    }

    @Test
    void testCanManageRealm_Success() {
        when(realmAuthorizationService.canManageRealm("user-1", "realm1")).thenReturn(true);

        Response response = realmAssignmentResource.canManageRealm("user-1", "realm1");

        assertEquals(Response.Status.OK.getStatusCode(), response.getStatus());
        RealmAssignmentResource.CheckResponse checkResponse = (RealmAssignmentResource.CheckResponse) response.getEntity();
        assertTrue(checkResponse.canManage);
    }

    @Test
    void testGetAuthorizedRealms_Success() {
        List<String> realms = Arrays.asList("realm1", "realm2");
        when(realmAuthorizationService.getAuthorizedRealms("user-1")).thenReturn(realms);
        when(realmAuthorizationService.isSuperAdmin("user-1")).thenReturn(false);

        Response response = realmAssignmentResource.getAuthorizedRealms("user-1");

        assertEquals(Response.Status.OK.getStatusCode(), response.getStatus());
        RealmAssignmentResource.AuthorizedRealmsResponse authResponse = 
            (RealmAssignmentResource.AuthorizedRealmsResponse) response.getEntity();
        assertEquals(2, authResponse.realms.size());
        assertFalse(authResponse.isSuperAdmin);
    }

    @Test
    void testAssignRealmToUser_Success() {
        when(securityContext.getUserPrincipal()).thenReturn(principal);
        when(principal.getName()).thenReturn("admin");
        when(realmAuthorizationService.assignRealmToUser(any(RealmAssignmentDTO.class))).thenReturn(assignment);

        Response response = realmAssignmentResource.assignRealmToUser(assignment);

        assertEquals(Response.Status.CREATED.getStatusCode(), response.getStatus());
    }

    @Test
    void testAssignRealmToUser_Conflict() {
        when(securityContext.getUserPrincipal()).thenReturn(principal);
        when(principal.getName()).thenReturn("admin");
        when(realmAuthorizationService.assignRealmToUser(any(RealmAssignmentDTO.class)))
            .thenThrow(new IllegalArgumentException("Already exists"));

        Response response = realmAssignmentResource.assignRealmToUser(assignment);

        assertEquals(Response.Status.CONFLICT.getStatusCode(), response.getStatus());
    }

    @Test
    void testRevokeRealmFromUser_Success() {
        doNothing().when(realmAuthorizationService).revokeRealmFromUser("user-1", "realm1");

        Response response = realmAssignmentResource.revokeRealmFromUser("user-1", "realm1");

        assertEquals(Response.Status.NO_CONTENT.getStatusCode(), response.getStatus());
    }

    @Test
    void testRevokeAllRealmsFromUser_Success() {
        doNothing().when(realmAuthorizationService).revokeAllRealmsFromUser("user-1");

        Response response = realmAssignmentResource.revokeAllRealmsFromUser("user-1");

        assertEquals(Response.Status.NO_CONTENT.getStatusCode(), response.getStatus());
    }

    @Test
    void testDeactivateAssignment_Success() {
        doNothing().when(realmAuthorizationService).deactivateAssignment("assignment-1");

        Response response = realmAssignmentResource.deactivateAssignment("assignment-1");

        assertEquals(Response.Status.NO_CONTENT.getStatusCode(), response.getStatus());
    }

    @Test
    void testDeactivateAssignment_NotFound() {
        doThrow(new IllegalArgumentException("Not found"))
            .when(realmAuthorizationService).deactivateAssignment("non-existent");

        Response response = realmAssignmentResource.deactivateAssignment("non-existent");

        assertEquals(Response.Status.NOT_FOUND.getStatusCode(), response.getStatus());
    }

    @Test
    void testActivateAssignment_Success() {
        doNothing().when(realmAuthorizationService).activateAssignment("assignment-1");

        Response response = realmAssignmentResource.activateAssignment("assignment-1");

        assertEquals(Response.Status.NO_CONTENT.getStatusCode(), response.getStatus());
    }

    @Test
    void testSetSuperAdmin_Success() {
        doNothing().when(realmAuthorizationService).setSuperAdmin("user-1", true);

        Response response = realmAssignmentResource.setSuperAdmin("user-1", true);

        assertEquals(Response.Status.NO_CONTENT.getStatusCode(), response.getStatus());
    }
}

