package dev.lions.user.manager.service.impl;

import dev.lions.user.manager.client.KeycloakAdminClient;
import dev.lions.user.manager.dto.role.RoleDTO;
import dev.lions.user.manager.enums.role.TypeRole;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.keycloak.admin.client.Keycloak;
import org.keycloak.admin.client.resource.*;
import org.keycloak.representations.idm.ClientRepresentation;
import org.keycloak.representations.idm.RoleRepresentation;
import org.keycloak.representations.idm.UserRepresentation;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.junit.jupiter.MockitoExtension;

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 supplémentaires pour RoleServiceImpl pour améliorer la couverture
 * Couvre les méthodes : userHasRole, roleExists, countUsersWithRole
 */
@ExtendWith(MockitoExtension.class)
class RoleServiceImplExtendedTest {

    @Mock
    private KeycloakAdminClient keycloakAdminClient;

    @Mock
    private Keycloak keycloakInstance;

    @Mock
    private RealmResource realmResource;

    @Mock
    private RolesResource rolesResource;

    @Mock
    private RoleResource roleResource;

    @Mock
    private UsersResource usersResource;

    @Mock
    private UserResource userResource;

    @Mock
    private RoleMappingResource roleMappingResource;

    @Mock
    private RoleScopeResource realmLevelRoleScopeResource;

    @Mock
    private RoleScopeResource clientLevelRoleScopeResource;

    @Mock
    private ClientsResource clientsResource;

    @InjectMocks
    private RoleServiceImpl roleService;

    private static final String REALM = "test-realm";
    private static final String USER_ID = "user-123";
    private static final String ROLE_NAME = "admin";
    private static final String CLIENT_NAME = "test-client";

    @Test
    void testUserHasRole_RealmRole_True() {
        when(keycloakAdminClient.getInstance()).thenReturn(keycloakInstance);
        when(keycloakInstance.realm(REALM)).thenReturn(realmResource);
        when(realmResource.users()).thenReturn(usersResource);
        when(usersResource.get(USER_ID)).thenReturn(userResource);
        when(userResource.roles()).thenReturn(roleMappingResource);
        when(roleMappingResource.realmLevel()).thenReturn(realmLevelRoleScopeResource);

        RoleRepresentation role = new RoleRepresentation();
        role.setName(ROLE_NAME);
        when(realmLevelRoleScopeResource.listEffective()).thenReturn(List.of(role));

        boolean result = roleService.userHasRole(USER_ID, ROLE_NAME, REALM, TypeRole.REALM_ROLE, null);

        assertTrue(result);
    }

    @Test
    void testUserHasRole_RealmRole_False() {
        when(keycloakAdminClient.getInstance()).thenReturn(keycloakInstance);
        when(keycloakInstance.realm(REALM)).thenReturn(realmResource);
        when(realmResource.users()).thenReturn(usersResource);
        when(usersResource.get(USER_ID)).thenReturn(userResource);
        when(userResource.roles()).thenReturn(roleMappingResource);
        when(roleMappingResource.realmLevel()).thenReturn(realmLevelRoleScopeResource);
        when(realmLevelRoleScopeResource.listEffective()).thenReturn(Collections.emptyList());

        boolean result = roleService.userHasRole(USER_ID, ROLE_NAME, REALM, TypeRole.REALM_ROLE, null);

        assertFalse(result);
    }

    @Test
    void testUserHasRole_ClientRole_True() {
        when(keycloakAdminClient.getInstance()).thenReturn(keycloakInstance);
        when(keycloakInstance.realm(REALM)).thenReturn(realmResource);
        when(realmResource.clients()).thenReturn(clientsResource);
        when(realmResource.users()).thenReturn(usersResource);
        when(usersResource.get(USER_ID)).thenReturn(userResource);
        when(userResource.roles()).thenReturn(roleMappingResource);

        ClientRepresentation client = new ClientRepresentation();
        client.setId("client-123");
        when(clientsResource.findByClientId(CLIENT_NAME)).thenReturn(List.of(client));
        when(roleMappingResource.clientLevel("client-123")).thenReturn(clientLevelRoleScopeResource);

        RoleRepresentation role = new RoleRepresentation();
        role.setName(ROLE_NAME);
        when(clientLevelRoleScopeResource.listEffective()).thenReturn(List.of(role));

        boolean result = roleService.userHasRole(USER_ID, ROLE_NAME, REALM, TypeRole.CLIENT_ROLE, CLIENT_NAME);

        assertTrue(result);
    }

    @Test
    void testUserHasRole_ClientRole_ClientNotFound() {
        when(keycloakAdminClient.getInstance()).thenReturn(keycloakInstance);
        when(keycloakInstance.realm(REALM)).thenReturn(realmResource);
        when(realmResource.clients()).thenReturn(clientsResource);
        when(clientsResource.findByClientId(CLIENT_NAME)).thenReturn(Collections.emptyList());

        boolean result = roleService.userHasRole(USER_ID, ROLE_NAME, REALM, TypeRole.CLIENT_ROLE, CLIENT_NAME);

        assertFalse(result);
    }

    @Test
    void testUserHasRole_ClientRole_NullClientName() {
        boolean result = roleService.userHasRole(USER_ID, ROLE_NAME, REALM, TypeRole.CLIENT_ROLE, null);

        assertFalse(result);
    }

    @Test
    void testRoleExists_RealmRole_True() {
        when(keycloakAdminClient.getInstance()).thenReturn(keycloakInstance);
        when(keycloakInstance.realm(REALM)).thenReturn(realmResource);
        when(realmResource.roles()).thenReturn(rolesResource);
        when(rolesResource.get(ROLE_NAME)).thenReturn(roleResource);

        RoleRepresentation role = new RoleRepresentation();
        role.setName(ROLE_NAME);
        when(roleResource.toRepresentation()).thenReturn(role);

        boolean result = roleService.roleExists(ROLE_NAME, REALM, TypeRole.REALM_ROLE, null);

        assertTrue(result);
    }

    @Test
    void testRoleExists_RealmRole_False() {
        when(keycloakAdminClient.getInstance()).thenReturn(keycloakInstance);
        when(keycloakInstance.realm(REALM)).thenReturn(realmResource);
        when(realmResource.roles()).thenReturn(rolesResource);
        when(rolesResource.get(ROLE_NAME)).thenReturn(roleResource);
        when(roleResource.toRepresentation()).thenThrow(new jakarta.ws.rs.NotFoundException());

        boolean result = roleService.roleExists(ROLE_NAME, REALM, TypeRole.REALM_ROLE, null);

        assertFalse(result);
    }

    @Test
    void testCountUsersWithRole_Success() {
        when(keycloakAdminClient.getInstance()).thenReturn(keycloakInstance);
        when(keycloakInstance.realm(REALM)).thenReturn(realmResource);
        when(realmResource.roles()).thenReturn(rolesResource);
        when(realmResource.users()).thenReturn(usersResource);

        // Mock getRoleById
        RoleRepresentation roleRep = new RoleRepresentation();
        roleRep.setId("role-123");
        roleRep.setName(ROLE_NAME);
        when(rolesResource.list()).thenReturn(List.of(roleRep));

        // Mock user list
        UserRepresentation user1 = new UserRepresentation();
        user1.setId("user-1");
        UserRepresentation user2 = new UserRepresentation();
        user2.setId("user-2");
        when(usersResource.list()).thenReturn(List.of(user1, user2));

        // Mock userHasRole for each user
        when(usersResource.get("user-1")).thenReturn(userResource);
        when(usersResource.get("user-2")).thenReturn(userResource);
        when(userResource.roles()).thenReturn(roleMappingResource);
        when(roleMappingResource.realmLevel()).thenReturn(realmLevelRoleScopeResource);

        RoleRepresentation role = new RoleRepresentation();
        role.setName(ROLE_NAME);
        // User 1 has role, user 2 doesn't
        when(realmLevelRoleScopeResource.listEffective())
            .thenReturn(List.of(role))  // user-1
            .thenReturn(Collections.emptyList()); // user-2

        long count = roleService.countUsersWithRole("role-123", REALM, TypeRole.REALM_ROLE, null);

        assertEquals(1, count);
    }

    @Test
    void testCountUsersWithRole_RoleNotFound() {
        when(keycloakAdminClient.getInstance()).thenReturn(keycloakInstance);
        when(keycloakInstance.realm(REALM)).thenReturn(realmResource);
        when(realmResource.roles()).thenReturn(rolesResource);
        when(rolesResource.list()).thenReturn(Collections.emptyList());

        long count = roleService.countUsersWithRole("non-existent-role", REALM, TypeRole.REALM_ROLE, null);

        assertEquals(0, count);
    }

    @Test
    void testCountUsersWithRole_Exception() {
        when(keycloakAdminClient.getInstance()).thenReturn(keycloakInstance);
        when(keycloakInstance.realm(REALM)).thenReturn(realmResource);
        when(realmResource.roles()).thenReturn(rolesResource);
        when(realmResource.users()).thenReturn(usersResource);

        RoleRepresentation roleRep = new RoleRepresentation();
        roleRep.setId("role-123");
        roleRep.setName(ROLE_NAME);
        when(rolesResource.list()).thenReturn(List.of(roleRep));
        when(usersResource.list()).thenThrow(new RuntimeException("Error"));

        long count = roleService.countUsersWithRole("role-123", REALM, TypeRole.REALM_ROLE, null);

        assertEquals(0, count);
    }
}

