package dev.lions.user.manager.config;

import io.quarkus.runtime.StartupEvent;
import jakarta.ws.rs.NotFoundException;
import jakarta.ws.rs.core.Response;
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.KeycloakBuilder;
import org.keycloak.admin.client.resource.*;
import org.keycloak.representations.idm.*;
import org.mockito.MockedStatic;
import org.mockito.junit.jupiter.MockitoExtension;

import java.lang.reflect.Method;
import java.net.URI;
import java.util.ArrayList;
import java.util.Arrays;
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 complets pour KeycloakTestUserConfig pour atteindre 100% de couverture
 * Teste toutes les méthodes privées via la méthode publique onStart
 */
@ExtendWith(MockitoExtension.class)
class KeycloakTestUserConfigCompleteTest {

    private KeycloakTestUserConfig config;
    private Keycloak adminClient;
    private RealmsResource realmsResource;
    private RealmResource realmResource;
    private RolesResource rolesResource;
    private RoleResource roleResource;
    private UsersResource usersResource;
    private UserResource userResource;
    private ClientsResource clientsResource;
    private ClientResource clientResource;
    private ClientScopesResource clientScopesResource;
    private ClientScopeResource clientScopeResource;

    @BeforeEach
    void setUp() throws Exception {
        config = new KeycloakTestUserConfig();
        
        // Injecter les valeurs via reflection
        setField("profile", "dev");
        setField("keycloakServerUrl", "http://localhost:8080");
        setField("adminRealm", "master");
        setField("adminUsername", "admin");
        setField("adminPassword", "admin");
        setField("authorizedRealms", "lions-user-manager");

        // Mocks pour Keycloak
        adminClient = mock(Keycloak.class);
        realmsResource = mock(RealmsResource.class);
        realmResource = mock(RealmResource.class);
        rolesResource = mock(RolesResource.class);
        roleResource = mock(RoleResource.class);
        usersResource = mock(UsersResource.class);
        userResource = mock(UserResource.class);
        clientsResource = mock(ClientsResource.class);
        clientResource = mock(ClientResource.class);
        clientScopesResource = mock(ClientScopesResource.class);
        clientScopeResource = mock(ClientScopeResource.class);
    }

    private void setField(String fieldName, Object value) throws Exception {
        java.lang.reflect.Field field = KeycloakTestUserConfig.class.getDeclaredField(fieldName);
        field.setAccessible(true);
        field.set(config, value);
    }

    @Test
    void testOnStart_DevMode() {
        // Le code est désactivé, donc onStart devrait juste logger et retourner
        StartupEvent event = mock(StartupEvent.class);
        
        // Ne devrait pas lancer d'exception
        assertDoesNotThrow(() -> config.onStart(event));
    }

    @Test
    void testEnsureRealmExists_RealmExists() throws Exception {
        when(adminClient.realms()).thenReturn(realmsResource);
        when(realmsResource.realm("lions-user-manager")).thenReturn(realmResource);
        when(realmResource.toRepresentation()).thenReturn(new RealmRepresentation());

        Method method = KeycloakTestUserConfig.class.getDeclaredMethod("ensureRealmExists", Keycloak.class);
        method.setAccessible(true);
        
        assertDoesNotThrow(() -> method.invoke(config, adminClient));
        verify(realmResource).toRepresentation();
    }

    @Test
    void testEnsureRealmExists_RealmNotFound() throws Exception {
        when(adminClient.realms()).thenReturn(realmsResource);
        when(realmsResource.realm("lions-user-manager")).thenReturn(realmResource);
        when(realmResource.toRepresentation()).thenThrow(new NotFoundException());
        doNothing().when(realmsResource).create(any(RealmRepresentation.class));

        Method method = KeycloakTestUserConfig.class.getDeclaredMethod("ensureRealmExists", Keycloak.class);
        method.setAccessible(true);
        
        assertDoesNotThrow(() -> method.invoke(config, adminClient));
        verify(realmResource).toRepresentation();
    }

    @Test
    void testEnsureRolesExist_AllRolesExist() throws Exception {
        when(adminClient.realms()).thenReturn(realmsResource);
        when(realmsResource.realm("lions-user-manager")).thenReturn(realmResource);
        when(realmResource.roles()).thenReturn(rolesResource);
        when(rolesResource.get(anyString())).thenReturn(roleResource);
        when(roleResource.toRepresentation()).thenReturn(new RoleRepresentation());

        Method method = KeycloakTestUserConfig.class.getDeclaredMethod("ensureRolesExist", Keycloak.class);
        method.setAccessible(true);
        
        assertDoesNotThrow(() -> method.invoke(config, adminClient));
    }

    @Test
    void testEnsureRolesExist_RoleNotFound() throws Exception {
        when(adminClient.realms()).thenReturn(realmsResource);
        when(realmsResource.realm("lions-user-manager")).thenReturn(realmResource);
        when(realmResource.roles()).thenReturn(rolesResource);
        when(rolesResource.get(anyString())).thenReturn(roleResource);
        when(roleResource.toRepresentation())
            .thenThrow(new NotFoundException())
            .thenReturn(new RoleRepresentation());
        doNothing().when(rolesResource).create(any(RoleRepresentation.class));

        Method method = KeycloakTestUserConfig.class.getDeclaredMethod("ensureRolesExist", Keycloak.class);
        method.setAccessible(true);
        
        assertDoesNotThrow(() -> method.invoke(config, adminClient));
    }

    @Test
    void testEnsureTestUserExists_UserExists() throws Exception {
        when(adminClient.realms()).thenReturn(realmsResource);
        when(realmsResource.realm("lions-user-manager")).thenReturn(realmResource);
        when(realmResource.users()).thenReturn(usersResource);
        
        UserRepresentation existingUser = new UserRepresentation();
        existingUser.setId("user-id-123");
        when(usersResource.search("test-user", true)).thenReturn(List.of(existingUser));

        Method method = KeycloakTestUserConfig.class.getDeclaredMethod("ensureTestUserExists", Keycloak.class);
        method.setAccessible(true);
        
        String userId = (String) method.invoke(config, adminClient);
        assertEquals("user-id-123", userId);
    }

    @Test
    void testEnsureTestUserExists_UserNotFound() throws Exception {
        when(adminClient.realms()).thenReturn(realmsResource);
        when(realmsResource.realm("lions-user-manager")).thenReturn(realmResource);
        when(realmResource.users()).thenReturn(usersResource);
        when(usersResource.search("test-user", true)).thenReturn(Collections.emptyList());
        
        Response response = mock(Response.class);
        when(response.getStatusInfo()).thenReturn(Response.Status.CREATED);
        when(response.getLocation()).thenReturn(URI.create("http://localhost/users/user-id-123"));
        when(usersResource.create(any(UserRepresentation.class))).thenReturn(response);
        when(usersResource.get("user-id-123")).thenReturn(userResource);
        
        CredentialRepresentation credential = new CredentialRepresentation();
        doNothing().when(userResource).resetPassword(any(CredentialRepresentation.class));

        Method method = KeycloakTestUserConfig.class.getDeclaredMethod("ensureTestUserExists", Keycloak.class);
        method.setAccessible(true);
        
        String userId = (String) method.invoke(config, adminClient);
        assertEquals("user-id-123", userId);
        verify(usersResource).create(any(UserRepresentation.class));
        verify(userResource).resetPassword(any(CredentialRepresentation.class));
    }

    @Test
    void testAssignRolesToUser() throws Exception {
        when(adminClient.realms()).thenReturn(realmsResource);
        when(realmsResource.realm("lions-user-manager")).thenReturn(realmResource);
        when(realmResource.users()).thenReturn(usersResource);
        when(realmResource.roles()).thenReturn(rolesResource);
        when(rolesResource.get(anyString())).thenReturn(roleResource);
        
        RoleRepresentation role = new RoleRepresentation();
        role.setName("admin");
        when(roleResource.toRepresentation()).thenReturn(role);
        
        when(usersResource.get("user-id")).thenReturn(userResource);
        RoleMappingResource roleMappingResource = mock(RoleMappingResource.class);
        RoleScopeResource roleScopeResource = mock(RoleScopeResource.class);
        when(userResource.roles()).thenReturn(roleMappingResource);
        when(roleMappingResource.realmLevel()).thenReturn(roleScopeResource);
        doNothing().when(roleScopeResource).add(anyList());

        Method method = KeycloakTestUserConfig.class.getDeclaredMethod("assignRolesToUser", Keycloak.class, String.class);
        method.setAccessible(true);
        
        assertDoesNotThrow(() -> method.invoke(config, adminClient, "user-id"));
        verify(roleScopeResource).add(anyList());
    }

    @Test
    void testEnsureClientAndMapper_ClientExists() throws Exception {
        when(adminClient.realms()).thenReturn(realmsResource);
        when(realmsResource.realm("lions-user-manager")).thenReturn(realmResource);
        when(realmResource.clients()).thenReturn(clientsResource);
        
        ClientRepresentation existingClient = new ClientRepresentation();
        existingClient.setId("client-id-123");
        when(clientsResource.findByClientId("lions-user-manager-client")).thenReturn(List.of(existingClient));
        
        when(realmResource.clientScopes()).thenReturn(clientScopesResource);
        ClientScopeRepresentation rolesScope = new ClientScopeRepresentation();
        rolesScope.setId("scope-id");
        rolesScope.setName("roles");
        when(clientScopesResource.findAll()).thenReturn(List.of(rolesScope));
        
        when(clientsResource.get("client-id-123")).thenReturn(clientResource);
        when(clientResource.getDefaultClientScopes()).thenReturn(List.of(rolesScope));

        Method method = KeycloakTestUserConfig.class.getDeclaredMethod("ensureClientAndMapper", Keycloak.class);
        method.setAccessible(true);
        
        assertDoesNotThrow(() -> method.invoke(config, adminClient));
    }

    @Test
    void testEnsureClientAndMapper_ClientNotFound() throws Exception {
        when(adminClient.realms()).thenReturn(realmsResource);
        when(realmsResource.realm("lions-user-manager")).thenReturn(realmResource);
        when(realmResource.clients()).thenReturn(clientsResource);
        when(clientsResource.findByClientId("lions-user-manager-client")).thenReturn(Collections.emptyList());
        
        Response response = mock(Response.class);
        when(response.getStatusInfo()).thenReturn(Response.Status.CREATED);
        when(response.getLocation()).thenReturn(URI.create("http://localhost/clients/client-id-123"));
        when(clientsResource.create(any(ClientRepresentation.class))).thenReturn(response);
        
        when(realmResource.clientScopes()).thenReturn(clientScopesResource);
        ClientScopeRepresentation rolesScope = new ClientScopeRepresentation();
        rolesScope.setId("scope-id");
        rolesScope.setName("roles");
        when(clientScopesResource.findAll()).thenReturn(List.of(rolesScope));
        
        when(clientsResource.get("client-id-123")).thenReturn(clientResource);
        when(clientResource.getDefaultClientScopes()).thenReturn(List.of(rolesScope));

        Method method = KeycloakTestUserConfig.class.getDeclaredMethod("ensureClientAndMapper", Keycloak.class);
        method.setAccessible(true);
        
        assertDoesNotThrow(() -> method.invoke(config, adminClient));
        verify(clientsResource).create(any(ClientRepresentation.class));
    }

    @Test
    void testEnsureClientAndMapper_ClientNotFound_NoRolesScope() throws Exception {
        when(adminClient.realms()).thenReturn(realmsResource);
        when(realmsResource.realm("lions-user-manager")).thenReturn(realmResource);
        when(realmResource.clients()).thenReturn(clientsResource);
        when(clientsResource.findByClientId("lions-user-manager-client")).thenReturn(Collections.emptyList());
        
        Response response = mock(Response.class);
        when(response.getStatusInfo()).thenReturn(Response.Status.CREATED);
        when(response.getLocation()).thenReturn(URI.create("http://localhost/clients/client-id-123"));
        when(clientsResource.create(any(ClientRepresentation.class))).thenReturn(response);
        
        when(realmResource.clientScopes()).thenReturn(clientScopesResource);
        when(clientScopesResource.findAll()).thenReturn(Collections.emptyList());

        Method method = KeycloakTestUserConfig.class.getDeclaredMethod("ensureClientAndMapper", Keycloak.class);
        method.setAccessible(true);
        
        assertDoesNotThrow(() -> method.invoke(config, adminClient));
    }

    @Test
    void testEnsureClientAndMapper_ClientNotFound_RolesScopeAlreadyPresent() throws Exception {
        when(adminClient.realms()).thenReturn(realmsResource);
        when(realmsResource.realm("lions-user-manager")).thenReturn(realmResource);
        when(realmResource.clients()).thenReturn(clientsResource);
        when(clientsResource.findByClientId("lions-user-manager-client")).thenReturn(Collections.emptyList());
        
        Response response = mock(Response.class);
        when(response.getStatusInfo()).thenReturn(Response.Status.CREATED);
        when(response.getLocation()).thenReturn(URI.create("http://localhost/clients/client-id-123"));
        when(clientsResource.create(any(ClientRepresentation.class))).thenReturn(response);
        
        when(realmResource.clientScopes()).thenReturn(clientScopesResource);
        ClientScopeRepresentation rolesScope = new ClientScopeRepresentation();
        rolesScope.setId("scope-id");
        rolesScope.setName("roles");
        when(clientScopesResource.findAll()).thenReturn(List.of(rolesScope));
        
        when(clientsResource.get("client-id-123")).thenReturn(clientResource);
        // Simuler que le scope "roles" est déjà présent
        when(clientResource.getDefaultClientScopes()).thenReturn(List.of(rolesScope));

        Method method = KeycloakTestUserConfig.class.getDeclaredMethod("ensureClientAndMapper", Keycloak.class);
        method.setAccessible(true);
        
        assertDoesNotThrow(() -> method.invoke(config, adminClient));
    }

    @Test
    void testEnsureClientAndMapper_Exception() throws Exception {
        when(adminClient.realms()).thenReturn(realmsResource);
        when(realmsResource.realm("lions-user-manager")).thenReturn(realmResource);
        when(realmResource.clients()).thenReturn(clientsResource);
        when(clientsResource.findByClientId("lions-user-manager-client")).thenThrow(new RuntimeException("Connection error"));

        Method method = KeycloakTestUserConfig.class.getDeclaredMethod("ensureClientAndMapper", Keycloak.class);
        method.setAccessible(true);
        
        assertDoesNotThrow(() -> method.invoke(config, adminClient));
    }

    @Test
    void testGetCreatedId_Success() throws Exception {
        Response response = mock(Response.class);
        when(response.getStatusInfo()).thenReturn(Response.Status.CREATED);
        when(response.getLocation()).thenReturn(URI.create("http://localhost/users/user-id-123"));

        Method method = KeycloakTestUserConfig.class.getDeclaredMethod("getCreatedId", Response.class);
        method.setAccessible(true);
        
        String id = (String) method.invoke(config, response);
        assertEquals("user-id-123", id);
    }

    @Test
    void testGetCreatedId_Error() throws Exception {
        Response response = mock(Response.class);
        // Utiliser Response.Status.BAD_REQUEST directement
        when(response.getStatusInfo()).thenReturn(Response.Status.BAD_REQUEST);

        Method method = KeycloakTestUserConfig.class.getDeclaredMethod("getCreatedId", Response.class);
        method.setAccessible(true);
        
        Exception exception = assertThrows(Exception.class, () -> method.invoke(config, response));
        assertTrue(exception.getCause() instanceof RuntimeException);
        assertTrue(exception.getCause().getMessage().contains("Erreur lors de la création"));
    }
}

