package dev.lions.unionflow.server.service;

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

import dev.lions.unionflow.server.api.dto.logs.response.SystemMetricsResponse;
import dev.lions.unionflow.server.repository.MembreRepository;
import io.agroal.api.AgroalDataSource;
import io.agroal.api.AgroalDataSourceMetrics;
import io.agroal.api.configuration.AgroalConnectionPoolConfiguration;
import io.agroal.api.configuration.AgroalDataSourceConfiguration;
import io.quarkus.test.InjectMock;
import io.quarkus.test.junit.QuarkusTest;
import jakarta.inject.Inject;
import java.sql.Connection;
import java.sql.SQLException;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;

/**
 * Tests complémentaires pour {@link SystemMetricsService} — cas limites de getCpuUsage,
 * getDiskUsagePercent et des méthodes de pool de connexions DB.
 */
@QuarkusTest
class SystemMetricsServiceCoverageTest {

    @Inject
    SystemMetricsService systemMetricsService;

    @InjectMock
    AgroalDataSource agroalDataSource;

    @InjectMock
    MembreRepository membreRepository;

    @BeforeEach
    void setupDefaultMocks() throws SQLException {
        Connection conn = mock(Connection.class);
        when(conn.isValid(5)).thenReturn(true);
        when(agroalDataSource.getConnection()).thenReturn(conn);

        when(membreRepository.count(anyString(), (Object[]) any())).thenReturn(5L);
        when(membreRepository.count()).thenReturn(10L);
    }

    @Test
    @DisplayName("getCpuUsage — résultat entre 0.0 et 100.0 quel que soit l'OS")
    void getCpuUsage_resultatEntre0Et100() throws SQLException {
        Connection conn = mock(Connection.class);
        when(conn.isValid(5)).thenReturn(true);
        when(agroalDataSource.getConnection()).thenReturn(conn);

        AgroalConnectionPoolConfiguration poolConfig = mock(AgroalConnectionPoolConfiguration.class);
        when(poolConfig.maxSize()).thenReturn(5);
        AgroalDataSourceConfiguration config = mock(AgroalDataSourceConfiguration.class);
        when(config.connectionPoolConfiguration()).thenReturn(poolConfig);
        when(agroalDataSource.getConfiguration()).thenReturn(config);

        AgroalDataSourceMetrics metrics = mock(AgroalDataSourceMetrics.class);
        when(metrics.activeCount()).thenReturn(1L);
        when(metrics.availableCount()).thenReturn(4L);
        when(agroalDataSource.getMetrics()).thenReturn(metrics);

        SystemMetricsResponse response = systemMetricsService.getSystemMetrics();

        // cpuUsagePercent doit toujours être entre 0 et 100
        assertThat(response.getCpuUsagePercent())
                .isNotNull()
                .isGreaterThanOrEqualTo(0.0)
                .isLessThanOrEqualTo(100.0);
    }

    @Test
    @DisplayName("getDbConnectionPoolSize — poolConfig null → retourne 0")
    void getDbConnectionPoolSize_poolConfigNull_retourne0() {
        AgroalDataSourceConfiguration config = mock(AgroalDataSourceConfiguration.class);
        // connectionPoolConfiguration() retourne null → poolConfig null → pool size = 0
        when(config.connectionPoolConfiguration()).thenReturn(null);
        when(agroalDataSource.getConfiguration()).thenReturn(config);

        // getMetrics() pour les autres méthodes (activeConnections, idleConnections)
        AgroalDataSourceMetrics metrics = mock(AgroalDataSourceMetrics.class);
        when(metrics.activeCount()).thenReturn(0L);
        when(metrics.availableCount()).thenReturn(0L);
        when(agroalDataSource.getMetrics()).thenReturn(metrics);

        SystemMetricsResponse response = systemMetricsService.getSystemMetrics();

        assertThat(response.getDbConnectionPoolSize()).isEqualTo(0);
    }

    @Test
    @DisplayName("getSystemMetrics — AgroalDataSource avec toutes métriques disponibles")
    void getSystemMetrics_agroal_cheminComplet() {
        AgroalConnectionPoolConfiguration poolConfig = mock(AgroalConnectionPoolConfiguration.class);
        when(poolConfig.maxSize()).thenReturn(20);

        AgroalDataSourceConfiguration config = mock(AgroalDataSourceConfiguration.class);
        when(config.connectionPoolConfiguration()).thenReturn(poolConfig);
        when(agroalDataSource.getConfiguration()).thenReturn(config);

        AgroalDataSourceMetrics metrics = mock(AgroalDataSourceMetrics.class);
        when(metrics.activeCount()).thenReturn(5L);
        when(metrics.availableCount()).thenReturn(15L);
        when(agroalDataSource.getMetrics()).thenReturn(metrics);

        SystemMetricsResponse response = systemMetricsService.getSystemMetrics();

        assertThat(response.getDbConnectionPoolSize()).isEqualTo(20);
        assertThat(response.getDbActiveConnections()).isEqualTo(5);
        assertThat(response.getDbIdleConnections()).isEqualTo(15);
    }

    @Test
    @DisplayName("getDbConnectionPoolSize — config null → retourne 0")
    void getDbConnectionPoolSize_configNull_retourne0() {
        when(agroalDataSource.getConfiguration()).thenReturn(null);
        // getMetrics() non stubbed → null → active et idle connections = 0

        SystemMetricsResponse response = systemMetricsService.getSystemMetrics();

        assertThat(response.getDbConnectionPoolSize()).isEqualTo(0);
        assertThat(response.getDbActiveConnections()).isEqualTo(0);
        assertThat(response.getDbIdleConnections()).isEqualTo(0);
    }

}
