package dev.lions.user.manager.client;

import org.junit.jupiter.api.BeforeEach;
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.RealmResource;
import org.keycloak.admin.client.resource.RolesResource;
import org.keycloak.admin.client.resource.UsersResource;
import org.keycloak.admin.client.token.TokenManager;
import org.keycloak.representations.info.ServerInfoRepresentation;
import org.keycloak.admin.client.resource.ServerInfoResource;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.junit.jupiter.MockitoExtension;

import jakarta.ws.rs.NotFoundException;
import java.lang.reflect.Field;
import java.util.List;

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

/**
 * Tests complets pour KeycloakAdminClientImpl
 */
@ExtendWith(MockitoExtension.class)
class KeycloakAdminClientImplCompleteTest {

    @Mock
    Keycloak mockKeycloak;

    @InjectMocks
    KeycloakAdminClientImpl client;

    private void setField(String fieldName, Object value) throws Exception {
        Field field = KeycloakAdminClientImpl.class.getDeclaredField(fieldName);
        field.setAccessible(true);
        field.set(client, value);
    }

    @BeforeEach
    void setUp() throws Exception {
        setField("serverUrl", "http://localhost:8180");
        setField("adminRealm", "master");
        setField("adminClientId", "admin-cli");
        setField("adminUsername", "admin");
    }

    @Test
    void testGetInstance() {
        Keycloak result = client.getInstance();
        assertSame(mockKeycloak, result);
    }

    @Test
    void testGetRealm_Success() {
        RealmResource mockRealmResource = mock(RealmResource.class);
        when(mockKeycloak.realm("test-realm")).thenReturn(mockRealmResource);

        RealmResource result = client.getRealm("test-realm");
        assertSame(mockRealmResource, result);
    }

    @Test
    void testGetRealm_Exception() {
        when(mockKeycloak.realm("bad-realm")).thenThrow(new RuntimeException("Connection error"));

        assertThrows(RuntimeException.class, () -> client.getRealm("bad-realm"));
    }

    @Test
    void testGetUsers() {
        RealmResource mockRealmResource = mock(RealmResource.class);
        UsersResource mockUsersResource = mock(UsersResource.class);
        when(mockKeycloak.realm("test-realm")).thenReturn(mockRealmResource);
        when(mockRealmResource.users()).thenReturn(mockUsersResource);

        UsersResource result = client.getUsers("test-realm");
        assertSame(mockUsersResource, result);
    }

    @Test
    void testGetRoles() {
        RealmResource mockRealmResource = mock(RealmResource.class);
        RolesResource mockRolesResource = mock(RolesResource.class);
        when(mockKeycloak.realm("test-realm")).thenReturn(mockRealmResource);
        when(mockRealmResource.roles()).thenReturn(mockRolesResource);

        RolesResource result = client.getRoles("test-realm");
        assertSame(mockRolesResource, result);
    }

    @Test
    void testIsConnected_True() {
        ServerInfoResource mockServerInfoResource = mock(ServerInfoResource.class);
        when(mockKeycloak.serverInfo()).thenReturn(mockServerInfoResource);
        when(mockServerInfoResource.getInfo()).thenReturn(mock(ServerInfoRepresentation.class));

        assertTrue(client.isConnected());
    }

    @Test
    void testIsConnected_False() {
        when(mockKeycloak.serverInfo()).thenThrow(new RuntimeException("Connection refused"));

        assertFalse(client.isConnected());
    }

    @Test
    void testRealmExists_True() {
        RealmResource mockRealmResource = mock(RealmResource.class);
        RolesResource mockRolesResource = mock(RolesResource.class);
        when(mockKeycloak.realm("test-realm")).thenReturn(mockRealmResource);
        when(mockRealmResource.roles()).thenReturn(mockRolesResource);
        when(mockRolesResource.list()).thenReturn(List.of());

        assertTrue(client.realmExists("test-realm"));
    }

    @Test
    void testRealmExists_NotFound() {
        RealmResource mockRealmResource = mock(RealmResource.class);
        RolesResource mockRolesResource = mock(RolesResource.class);
        when(mockKeycloak.realm("missing")).thenReturn(mockRealmResource);
        when(mockRealmResource.roles()).thenReturn(mockRolesResource);
        when(mockRolesResource.list()).thenThrow(new NotFoundException("Not found"));

        assertFalse(client.realmExists("missing"));
    }

    @Test
    void testRealmExists_OtherException() {
        when(mockKeycloak.realm("error-realm")).thenThrow(new RuntimeException("Other error"));

        assertTrue(client.realmExists("error-realm"));
    }

    @Test
    void testGetAllRealms_TokenError() {
        // When token retrieval fails, getAllRealms should throw
        when(mockKeycloak.tokenManager()).thenThrow(new RuntimeException("Token error"));

        assertThrows(RuntimeException.class, () -> client.getAllRealms());
    }

    @Test
    void testGetAllRealms_NullTokenManager() {
        when(mockKeycloak.tokenManager()).thenReturn(null);

        assertThrows(RuntimeException.class, () -> client.getAllRealms());
    }

    @Test
    void testClose() {
        assertDoesNotThrow(() -> client.close());
    }

    @Test
    void testReconnect() {
        assertDoesNotThrow(() -> client.reconnect());
    }
}
