package dev.lions.unionflow.server.api.dto.system.response;

import static org.assertj.core.api.Assertions.assertThat;

import java.time.LocalDateTime;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Nested;
import org.junit.jupiter.api.Test;

/**
 * Tests unitaires pour SystemMetricsResponse.
 * Couvre formatBytes, formatUptime, et tous les getters/setters via builder.
 *
 * @author UnionFlow Team
 * @version 1.0
 * @since 2026-03-07
 */
@DisplayName("Tests SystemMetricsResponse")
class SystemMetricsResponseTest {

  @Nested
  @DisplayName("formatBytes")
  class FormatBytes {

    @Test
    @DisplayName("retourne bytes pour moins de 1024")
    void testBytes() {
      assertThat(SystemMetricsResponse.formatBytes(0)).isEqualTo("0 B");
      assertThat(SystemMetricsResponse.formatBytes(512)).isEqualTo("512 B");
      assertThat(SystemMetricsResponse.formatBytes(1023)).isEqualTo("1023 B");
    }

    @Test
    @DisplayName("retourne KB pour 1024+")
    void testKiloBytes() {
      assertThat(SystemMetricsResponse.formatBytes(1024)).isEqualTo("1.0 KB");
      assertThat(SystemMetricsResponse.formatBytes(2048)).isEqualTo("2.0 KB");
      assertThat(SystemMetricsResponse.formatBytes(1536)).isEqualTo("1.5 KB");
    }

    @Test
    @DisplayName("retourne MB pour 1024*1024+")
    void testMegaBytes() {
      assertThat(SystemMetricsResponse.formatBytes(1024 * 1024)).isEqualTo("1.0 MB");
      assertThat(SystemMetricsResponse.formatBytes(5 * 1024 * 1024)).isEqualTo("5.0 MB");
    }

    @Test
    @DisplayName("retourne GB pour 1024*1024*1024+")
    void testGigaBytes() {
      assertThat(SystemMetricsResponse.formatBytes(1024L * 1024 * 1024)).isEqualTo("1.0 GB");
      assertThat(SystemMetricsResponse.formatBytes(3L * 1024 * 1024 * 1024)).isEqualTo("3.0 GB");
    }

    @Test
    @DisplayName("retourne TB pour 1024^4+")
    void testTeraBytes() {
      assertThat(SystemMetricsResponse.formatBytes(1024L * 1024 * 1024 * 1024)).isEqualTo("1.0 TB");
      assertThat(SystemMetricsResponse.formatBytes(2L * 1024 * 1024 * 1024 * 1024)).isEqualTo("2.0 TB");
    }

    @Test
    @DisplayName("retourne PB pour 1024^5+")
    void testPetaBytes() {
      assertThat(SystemMetricsResponse.formatBytes(1024L * 1024 * 1024 * 1024 * 1024))
          .isEqualTo("1.0 PB");
    }

    @Test
    @DisplayName("retourne EB pour 1024^6+")
    void testExaBytes() {
      assertThat(SystemMetricsResponse.formatBytes(1024L * 1024 * 1024 * 1024 * 1024 * 1024))
          .isEqualTo("1.0 EB");
    }
  }

  @Nested
  @DisplayName("formatUptime")
  class FormatUptime {

    @Test
    @DisplayName("retourne minutes seulement pour moins d'1h")
    void testMinutes() {
      assertThat(SystemMetricsResponse.formatUptime(0)).isEqualTo("0m");
      assertThat(SystemMetricsResponse.formatUptime(30 * 1000)).isEqualTo("0m");
      assertThat(SystemMetricsResponse.formatUptime(60 * 1000)).isEqualTo("1m");
      assertThat(SystemMetricsResponse.formatUptime(45 * 60 * 1000)).isEqualTo("45m");
    }

    @Test
    @DisplayName("retourne heures et minutes pour moins de 24h")
    void testHours() {
      assertThat(SystemMetricsResponse.formatUptime(60 * 60 * 1000)).isEqualTo("1h 0m");
      assertThat(SystemMetricsResponse.formatUptime(90 * 60 * 1000)).isEqualTo("1h 30m");
      assertThat(SystemMetricsResponse.formatUptime(5 * 60 * 60 * 1000 + 15 * 60 * 1000))
          .isEqualTo("5h 15m");
      assertThat(SystemMetricsResponse.formatUptime(23 * 60 * 60 * 1000 + 59 * 60 * 1000))
          .isEqualTo("23h 59m");
    }

    @Test
    @DisplayName("retourne jours, heures et minutes pour 24h+")
    void testDays() {
      assertThat(SystemMetricsResponse.formatUptime(24 * 60 * 60 * 1000L)).isEqualTo("1j 0h 0m");
      assertThat(SystemMetricsResponse.formatUptime(36 * 60 * 60 * 1000L)).isEqualTo("1j 12h 0m");
      assertThat(SystemMetricsResponse.formatUptime(
          5L * 24 * 60 * 60 * 1000 + 3 * 60 * 60 * 1000 + 30 * 60 * 1000))
          .isEqualTo("5j 3h 30m");
    }
  }

  @Nested
  @DisplayName("Builder et Getters")
  class BuilderGetters {

    @Test
    @DisplayName("tous les champs builder sont accessibles")
    void testBuilderGetters() {
      LocalDateTime now = LocalDateTime.now();
      SystemMetricsResponse dto = SystemMetricsResponse.builder()
          .cpuUsagePercent(23.5)
          .availableProcessors(8)
          .systemLoadAverage(1.5)
          .totalMemoryBytes(8589934592L)
          .usedMemoryBytes(5726623744L)
          .freeMemoryBytes(2863311248L)
          .maxMemoryBytes(17179869184L)
          .memoryUsagePercent(67.0)
          .totalMemoryFormatted("8.0 GB")
          .usedMemoryFormatted("5.4 GB")
          .freeMemoryFormatted("2.6 GB")
          .totalDiskBytes(500000000000L)
          .usedDiskBytes(225000000000L)
          .freeDiskBytes(275000000000L)
          .diskUsagePercent(45.0)
          .totalDiskFormatted("500 GB")
          .usedDiskFormatted("225 GB")
          .freeDiskFormatted("275 GB")
          .activeUsersCount(1247)
          .totalUsersCount(5000)
          .activeSessionsCount(500)
          .failedLoginAttempts24h(23)
          .apiRequestsLastHour(45892L)
          .apiRequestsToday(1234567L)
          .averageResponseTimeMs(127.5)
          .totalRequestsCount(9876543L)
          .dbConnectionPoolSize(10)
          .dbActiveConnections(5)
          .dbIdleConnections(5)
          .dbHealthy(true)
          .criticalErrorsCount(3)
          .warningsCount(27)
          .infoLogsCount(1247)
          .debugLogsCount(5892)
          .totalLogsCount(7169L)
          .networkBytesReceivedPerSec(12500000.0)
          .networkBytesSentPerSec(8200000.0)
          .networkInFormatted("12.5 MB/s")
          .networkOutFormatted("8.2 MB/s")
          .systemStatus("OPERATIONAL")
          .uptimeMillis(123456789L)
          .uptimeFormatted("1j 10h 17m")
          .startTime(now)
          .currentTime(now)
          .javaVersion("17.0.8")
          .quarkusVersion("3.15.1")
          .applicationVersion("1.0.0")
          .lastBackup(now)
          .nextScheduledMaintenance(now.plusDays(7))
          .lastMaintenance(now.minusDays(1))
          .apiBaseUrl("http://localhost:8085")
          .authServerUrl("http://localhost:8180/realms/unionflow")
          .cdnUrl("https://cdn.example.com")
          .totalCacheSizeBytes(471859200L)
          .totalCacheSizeFormatted("450 MB")
          .totalCacheEntries(1500)
          .build();

      assertThat(dto.getCpuUsagePercent()).isEqualTo(23.5);
      assertThat(dto.getAvailableProcessors()).isEqualTo(8);
      assertThat(dto.getSystemLoadAverage()).isEqualTo(1.5);
      assertThat(dto.getTotalMemoryBytes()).isEqualTo(8589934592L);
      assertThat(dto.getUsedMemoryBytes()).isEqualTo(5726623744L);
      assertThat(dto.getFreeMemoryBytes()).isEqualTo(2863311248L);
      assertThat(dto.getMaxMemoryBytes()).isEqualTo(17179869184L);
      assertThat(dto.getMemoryUsagePercent()).isEqualTo(67.0);
      assertThat(dto.getTotalMemoryFormatted()).isEqualTo("8.0 GB");
      assertThat(dto.getUsedMemoryFormatted()).isEqualTo("5.4 GB");
      assertThat(dto.getFreeMemoryFormatted()).isEqualTo("2.6 GB");
      assertThat(dto.getTotalDiskBytes()).isEqualTo(500000000000L);
      assertThat(dto.getUsedDiskBytes()).isEqualTo(225000000000L);
      assertThat(dto.getFreeDiskBytes()).isEqualTo(275000000000L);
      assertThat(dto.getDiskUsagePercent()).isEqualTo(45.0);
      assertThat(dto.getTotalDiskFormatted()).isEqualTo("500 GB");
      assertThat(dto.getUsedDiskFormatted()).isEqualTo("225 GB");
      assertThat(dto.getFreeDiskFormatted()).isEqualTo("275 GB");
      assertThat(dto.getActiveUsersCount()).isEqualTo(1247);
      assertThat(dto.getTotalUsersCount()).isEqualTo(5000);
      assertThat(dto.getActiveSessionsCount()).isEqualTo(500);
      assertThat(dto.getFailedLoginAttempts24h()).isEqualTo(23);
      assertThat(dto.getApiRequestsLastHour()).isEqualTo(45892L);
      assertThat(dto.getApiRequestsToday()).isEqualTo(1234567L);
      assertThat(dto.getAverageResponseTimeMs()).isEqualTo(127.5);
      assertThat(dto.getTotalRequestsCount()).isEqualTo(9876543L);
      assertThat(dto.getDbConnectionPoolSize()).isEqualTo(10);
      assertThat(dto.getDbActiveConnections()).isEqualTo(5);
      assertThat(dto.getDbIdleConnections()).isEqualTo(5);
      assertThat(dto.getDbHealthy()).isTrue();
      assertThat(dto.getCriticalErrorsCount()).isEqualTo(3);
      assertThat(dto.getWarningsCount()).isEqualTo(27);
      assertThat(dto.getInfoLogsCount()).isEqualTo(1247);
      assertThat(dto.getDebugLogsCount()).isEqualTo(5892);
      assertThat(dto.getTotalLogsCount()).isEqualTo(7169L);
      assertThat(dto.getNetworkBytesReceivedPerSec()).isEqualTo(12500000.0);
      assertThat(dto.getNetworkBytesSentPerSec()).isEqualTo(8200000.0);
      assertThat(dto.getNetworkInFormatted()).isEqualTo("12.5 MB/s");
      assertThat(dto.getNetworkOutFormatted()).isEqualTo("8.2 MB/s");
      assertThat(dto.getSystemStatus()).isEqualTo("OPERATIONAL");
      assertThat(dto.getUptimeMillis()).isEqualTo(123456789L);
      assertThat(dto.getUptimeFormatted()).isEqualTo("1j 10h 17m");
      assertThat(dto.getStartTime()).isEqualTo(now);
      assertThat(dto.getCurrentTime()).isEqualTo(now);
      assertThat(dto.getJavaVersion()).isEqualTo("17.0.8");
      assertThat(dto.getQuarkusVersion()).isEqualTo("3.15.1");
      assertThat(dto.getApplicationVersion()).isEqualTo("1.0.0");
      assertThat(dto.getLastBackup()).isEqualTo(now);
      assertThat(dto.getNextScheduledMaintenance()).isEqualTo(now.plusDays(7));
      assertThat(dto.getLastMaintenance()).isEqualTo(now.minusDays(1));
      assertThat(dto.getApiBaseUrl()).isEqualTo("http://localhost:8085");
      assertThat(dto.getAuthServerUrl()).isEqualTo("http://localhost:8180/realms/unionflow");
      assertThat(dto.getCdnUrl()).isEqualTo("https://cdn.example.com");
      assertThat(dto.getTotalCacheSizeBytes()).isEqualTo(471859200L);
      assertThat(dto.getTotalCacheSizeFormatted()).isEqualTo("450 MB");
      assertThat(dto.getTotalCacheEntries()).isEqualTo(1500);
    }

    @Test
    @DisplayName("builder avec valeurs nulles")
    void testBuilderNulls() {
      SystemMetricsResponse dto = SystemMetricsResponse.builder().build();
      assertThat(dto.getCpuUsagePercent()).isNull();
      assertThat(dto.getTotalMemoryBytes()).isNull();
      assertThat(dto.getSystemStatus()).isNull();
    }

    @Test
    @DisplayName("setters fonctionnent correctement")
    void testSetters() {
      SystemMetricsResponse dto = new SystemMetricsResponse();
      dto.setCpuUsagePercent(50.0);
      dto.setSystemStatus("DEGRADED");
      dto.setActiveUsersCount(100);

      assertThat(dto.getCpuUsagePercent()).isEqualTo(50.0);
      assertThat(dto.getSystemStatus()).isEqualTo("DEGRADED");
      assertThat(dto.getActiveUsersCount()).isEqualTo(100);
    }
  }
}
