package dev.lions.user.manager.resource;

import dev.lions.user.manager.service.SyncService;
import jakarta.ws.rs.core.Response;
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.util.Collections;
import java.util.List;
import java.util.Map;

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

@ExtendWith(MockitoExtension.class)
class SyncResourceTest {

    @Mock
    SyncService syncService;

    @InjectMocks
    SyncResource syncResource;

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

    @Test
    void testSyncUsers() {
        when(syncService.syncUsersFromRealm(REALM)).thenReturn(10);

        Response response = syncResource.syncUsers(REALM);

        assertEquals(200, response.getStatus());
        assertNotNull(response.getEntity());
    }

    @Test
    void testSyncUsersError() {
        when(syncService.syncUsersFromRealm(REALM)).thenThrow(new RuntimeException("Error"));

        Response response = syncResource.syncUsers(REALM);

        assertEquals(500, response.getStatus());
    }

    @Test
    void testSyncRealmRoles() {
        when(syncService.syncRolesFromRealm(REALM)).thenReturn(5);

        Response response = syncResource.syncRealmRoles(REALM);

        assertEquals(200, response.getStatus());
        assertNotNull(response.getEntity());
    }

    @Test
    void testSyncRealmRolesError() {
        when(syncService.syncRolesFromRealm(REALM)).thenThrow(new RuntimeException("Error"));

        Response response = syncResource.syncRealmRoles(REALM);

        assertEquals(500, response.getStatus());
    }

    @Test
    void testSyncClientRoles() {
        when(syncService.syncRolesFromRealm(REALM)).thenReturn(3);

        Response response = syncResource.syncClientRoles(CLIENT_ID, REALM);

        assertEquals(200, response.getStatus());
        assertNotNull(response.getEntity());
    }

    @Test
    void testSyncClientRolesError() {
        when(syncService.syncRolesFromRealm(REALM)).thenThrow(new RuntimeException("Error"));

        Response response = syncResource.syncClientRoles(CLIENT_ID, REALM);

        assertEquals(500, response.getStatus());
    }

    @Test
    void testSyncAll() {
        Map<String, Object> result = Map.of(
                "realmName", REALM,
                "usersSynced", 10,
                "rolesSynced", 5,
                "success", true
        );
        when(syncService.forceSyncRealm(REALM)).thenReturn(result);

        Response response = syncResource.syncAll(REALM);

        assertEquals(200, response.getStatus());
        assertEquals(result, response.getEntity());
    }

    @Test
    void testSyncAllError() {
        when(syncService.forceSyncRealm(REALM)).thenThrow(new RuntimeException("Error"));

        Response response = syncResource.syncAll(REALM);

        assertEquals(500, response.getStatus());
    }

    @Test
    void testCheckHealthHealthy() {
        when(syncService.isKeycloakAvailable()).thenReturn(true);

        Response response = syncResource.checkHealth();

        assertEquals(200, response.getStatus());
        assertNotNull(response.getEntity());
    }

    @Test
    void testCheckHealthUnhealthy() {
        when(syncService.isKeycloakAvailable()).thenReturn(false);

        Response response = syncResource.checkHealth();

        assertEquals(503, response.getStatus());
    }

    @Test
    void testCheckHealthError() {
        when(syncService.isKeycloakAvailable()).thenThrow(new RuntimeException("Error"));

        Response response = syncResource.checkHealth();

        assertEquals(503, response.getStatus());
    }

    @Test
    void testGetDetailedHealthStatus() {
        Map<String, Object> status = Map.of(
                "keycloakAvailable", true,
                "keycloakVersion", "21.0.0"
        );
        when(syncService.getKeycloakHealthInfo()).thenReturn(status);

        Response response = syncResource.getDetailedHealthStatus();

        assertEquals(200, response.getStatus());
        assertEquals(status, response.getEntity());
    }

    @Test
    void testGetDetailedHealthStatusError() {
        when(syncService.getKeycloakHealthInfo()).thenThrow(new RuntimeException("Error"));

        Response response = syncResource.getDetailedHealthStatus();

        assertEquals(500, response.getStatus());
    }

    @Test
    void testCheckRealmExistsTrue() {
        when(syncService.syncUsersFromRealm(REALM)).thenReturn(5);

        Response response = syncResource.checkRealmExists(REALM);

        assertEquals(200, response.getStatus());
        assertNotNull(response.getEntity());
    }

    @Test
    void testCheckRealmExistsFalse() {
        when(syncService.syncUsersFromRealm(REALM)).thenThrow(new RuntimeException("Realm not found"));

        Response response = syncResource.checkRealmExists(REALM);

        assertEquals(200, response.getStatus());
        assertNotNull(response.getEntity());
    }

    @Test
    void testCheckRealmExistsError() {
        when(syncService.syncUsersFromRealm(REALM)).thenThrow(new RuntimeException("Unexpected error"));

        Response response = syncResource.checkRealmExists(REALM);

        // checkRealmExists catches all exceptions and returns 200 with exists=false
        assertEquals(200, response.getStatus());
        assertNotNull(response.getEntity());
    }

    @Test
    void testCheckUserExists() {
        // La méthode checkUserExists retourne toujours false dans l'implémentation actuelle
        Response response = syncResource.checkUserExists("user1", REALM);

        assertEquals(200, response.getStatus());
        assertNotNull(response.getEntity());
    }

    @Test
    void testCheckUserExistsError() {
        // Test d'erreur si une exception est levée
        // Note: L'implémentation actuelle ne lève pas d'exception, mais testons quand même
        Response response = syncResource.checkUserExists("user1", REALM);

        assertEquals(200, response.getStatus());
    }

    // ============== Inner Class Tests ==============

    @Test
    void testSyncUsersResponseClass() {
        SyncResource.SyncUsersResponse response = new SyncResource.SyncUsersResponse(1, null);

        assertEquals(1, response.count);
        assertNull(response.users);
    }

    @Test
    void testSyncRolesResponseClass() {
        SyncResource.SyncRolesResponse response = new SyncResource.SyncRolesResponse(1, null);

        assertEquals(1, response.count);
        assertNull(response.roles);
    }

    @Test
    void testHealthCheckResponseClass() {
        SyncResource.HealthCheckResponse response = new SyncResource.HealthCheckResponse(true, "OK");

        assertTrue(response.healthy);
        assertEquals("OK", response.message);
    }

    @Test
    void testExistsCheckResponseClass() {
        SyncResource.ExistsCheckResponse response = new SyncResource.ExistsCheckResponse(true, "realm", "test");

        assertTrue(response.exists);
        assertEquals("realm", response.resourceType);
        assertEquals("test", response.resourceId);
    }

    @Test
    void testErrorResponseClass() {
        SyncResource.ErrorResponse response = new SyncResource.ErrorResponse("Error");
        assertEquals("Error", response.message);
    }
}
