package dev.lions.unionflow.server.service;

import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.junit.jupiter.MockitoExtension;

import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Map;

/**
 * Tests pour {@link AnalyticsService#convertirEnJSON} — branches du chemin try/catch.
 *
 * <p>Utilise l'instanciation directe + réflexion car {@code ObjectMapper} est un bean
 * {@code @Singleton} dans Quarkus et ne peut pas être mocké via {@code @InjectMock}
 * (qui requiert un scope CDI normal).
 */
@ExtendWith(MockitoExtension.class)
@DisplayName("AnalyticsService — convertirEnJSON branches (try/catch JsonProcessingException)")
class AnalyticsServiceConvertirEnJSONTest {

    /** Invoque la méthode privée convertirEnJSON sur une instance directe d'AnalyticsService. */
    private String invokeConvertirEnJSON(AnalyticsService service, Object data) throws Exception {
        Method method = AnalyticsService.class.getDeclaredMethod("convertirEnJSON", Object.class);
        method.setAccessible(true);
        return (String) method.invoke(service, data);
    }

    /** Crée une instance directe d'AnalyticsService avec l'ObjectMapper injecté via réflexion. */
    private AnalyticsService buildServiceWithMapper(ObjectMapper mapper) throws Exception {
        AnalyticsService service = new AnalyticsService();
        Field omField = AnalyticsService.class.getDeclaredField("objectMapper");
        omField.setAccessible(true);
        omField.set(service, mapper);
        return service;
    }

    // =========================================================================
    // Branche catch (JsonProcessingException e) — lignes 480-482
    // =========================================================================

    @Test
    @DisplayName("convertirEnJSON — JsonProcessingException → retourne '{}' (couvre L480-482)")
    void convertirEnJSON_jsonProcessingException_retourneObjetVide() throws Exception {
        ObjectMapper mockMapper = mock(ObjectMapper.class);
        when(mockMapper.writeValueAsString(any()))
                .thenThrow(new JsonProcessingException("Erreur de sérialisation simulée") {});

        AnalyticsService service = buildServiceWithMapper(mockMapper);

        String result = invokeConvertirEnJSON(service, new HashMap<>());

        assertThat(result).isEqualTo("{}");
    }

    // =========================================================================
    // Branche try (chemin normal) — ligne 479
    // =========================================================================

    @Test
    @DisplayName("convertirEnJSON — sérialisation réussie → retourne JSON non vide (couvre L479)")
    void convertirEnJSON_serialisationReussie_retourneJSON() throws Exception {
        AnalyticsService service = buildServiceWithMapper(new ObjectMapper());

        Map<String, Object> data = new HashMap<>();
        data.put("valeur", 42);
        data.put("devise", "XOF");

        String result = invokeConvertirEnJSON(service, data);

        assertThat(result).contains("valeur");
        assertThat(result).contains("42");
    }

    // =========================================================================
    // Branche data == null — ligne 477
    // =========================================================================

    @Test
    @DisplayName("convertirEnJSON — data null → retourne '{}' immédiatement (couvre L477)")
    void convertirEnJSON_nullData_retourneObjetVide() throws Exception {
        // Pas besoin d'ObjectMapper pour la branche null (retour direct avant writeValueAsString)
        AnalyticsService service = buildServiceWithMapper(new ObjectMapper());

        String result = invokeConvertirEnJSON(service, null);

        assertThat(result).isEqualTo("{}");
    }
}
