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

import dev.lions.user.manager.client.KeycloakAdminClient;
import dev.lions.user.manager.dto.role.RoleAssignmentDTO;
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.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.Optional;

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

@ExtendWith(MockitoExtension.class)
class RoleServiceImplTest {

    @Mock
    KeycloakAdminClient keycloakAdminClient;

    @Mock
    Keycloak keycloakInstance;

    @Mock
    RealmResource realmResource;

    @Mock
    RolesResource rolesResource;

    @Mock
    RoleResource roleResource;

    @Mock
    UsersResource usersResource;

    @Mock
    UserResource userResource;

    @Mock
    RoleMappingResource roleMappingResource;

    @Mock
    RoleScopeResource roleScopeResource;

    @InjectMocks
    RoleServiceImpl roleService;

    private static final String REALM = "test-realm";

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

        // Check not found initially, then return created role
        RoleRepresentation createdRep = new RoleRepresentation();
        createdRep.setName("role");
        createdRep.setId("1");
        when(rolesResource.get("role")).thenReturn(roleResource);
        when(roleResource.toRepresentation()).thenThrow(new jakarta.ws.rs.NotFoundException())
                .thenReturn(createdRep);

        // Mock create
        doNothing().when(rolesResource).create(any(RoleRepresentation.class));

        RoleDTO input = RoleDTO.builder().name("role").description("desc").build();

        RoleDTO result = roleService.createRealmRole(input, REALM);

        assertNotNull(result);
        assertEquals("role", result.getName());
    }

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

        // find by id logic uses list()
        RoleRepresentation rep = new RoleRepresentation();
        rep.setId("1");
        rep.setName("role");
        when(rolesResource.list()).thenReturn(Collections.singletonList(rep));

        roleService.deleteRole("1", REALM, TypeRole.REALM_ROLE, null);

        verify(rolesResource).deleteRole("role");
    }

    @Test
    void testAssignRolesToUser() {
        when(keycloakAdminClient.getInstance()).thenReturn(keycloakInstance);
        when(keycloakInstance.realm(REALM)).thenReturn(realmResource);
        when(realmResource.roles()).thenReturn(rolesResource);
        when(realmResource.users()).thenReturn(usersResource);
        when(usersResource.get("u1")).thenReturn(userResource);
        when(userResource.roles()).thenReturn(roleMappingResource);
        when(roleMappingResource.realmLevel()).thenReturn(roleScopeResource);

        RoleRepresentation roleRep = new RoleRepresentation();
        roleRep.setName("role1");
        when(rolesResource.get("role1")).thenReturn(roleResource);
        when(roleResource.toRepresentation()).thenReturn(roleRep);

        RoleAssignmentDTO assignment = RoleAssignmentDTO.builder()
                .userId("u1")
                .realmName(REALM)
                .typeRole(TypeRole.REALM_ROLE)
                .roleNames(Collections.singletonList("role1"))
                .build();

        roleService.assignRolesToUser(assignment);

        verify(roleScopeResource).add(anyList());
    }
}
