package dev.lions.unionflow.server.api.dto.dashboard;

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;

@DisplayName("Tests pour DashboardStatsDTO")
class DashboardStatsDTOTest {

  @Test
  @DisplayName("Test de base - classe peut être instanciée")
  void testClasseInstanciable() {
    DashboardStatsDTO dto = new DashboardStatsDTO();
    assertThat(dto).isNotNull();
  }

  @Nested
  @DisplayName("Tests de construction")
  class ConstructionTests {

    @Test
    @DisplayName("Constructeur par défaut")
    void testConstructeurParDefaut() {
      DashboardStatsDTO dto = new DashboardStatsDTO();

      assertThat(dto).isNotNull();
    }

    @Test
    @DisplayName("Builder pattern")
    void testBuilder() {
      LocalDateTime lastUpdated = LocalDateTime.now();
      DashboardStatsDTO dto = DashboardStatsDTO.builder()
          .totalMembers(100)
          .activeMembers(80)
          .totalEvents(50)
          .upcomingEvents(10)
          .totalContributions(200)
          .totalContributionAmount(50000.0)
          .pendingRequests(5)
          .completedProjects(15)
          .monthlyGrowth(5.5)
          .engagementRate(0.75)
          .lastUpdated(lastUpdated)
          .build();

      assertThat(dto.getTotalMembers()).isEqualTo(100);
      assertThat(dto.getActiveMembers()).isEqualTo(80);
      assertThat(dto.getTotalEvents()).isEqualTo(50);
      assertThat(dto.getUpcomingEvents()).isEqualTo(10);
      assertThat(dto.getTotalContributions()).isEqualTo(200);
      assertThat(dto.getTotalContributionAmount()).isEqualTo(50000.0);
      assertThat(dto.getPendingRequests()).isEqualTo(5);
      assertThat(dto.getCompletedProjects()).isEqualTo(15);
      assertThat(dto.getMonthlyGrowth()).isEqualTo(5.5);
      assertThat(dto.getEngagementRate()).isEqualTo(0.75);
      assertThat(dto.getLastUpdated()).isEqualTo(lastUpdated);
    }
  }

  @Nested
  @DisplayName("Tests getFormattedContributionAmount")
  class GetFormattedContributionAmountTests {

    @Test
    @DisplayName("getFormattedContributionAmount - montant >= 1M")
    void testGetFormattedContributionAmountMillions() {
      DashboardStatsDTO dto = DashboardStatsDTO.builder()
          .totalContributionAmount(1_500_000.0)
          .build();

      // Le format utilise la locale du système, peut être "1,5M" ou "1.5M"
      assertThat(dto.getFormattedContributionAmount()).matches("1[.,]5M");
    }

    @Test
    @DisplayName("getFormattedContributionAmount - montant >= 1K")
    void testGetFormattedContributionAmountMilliers() {
      DashboardStatsDTO dto = DashboardStatsDTO.builder()
          .totalContributionAmount(5_500.0)
          .build();

      assertThat(dto.getFormattedContributionAmount()).isEqualTo("6K");
    }

    @Test
    @DisplayName("getFormattedContributionAmount - montant < 1K")
    void testGetFormattedContributionAmountPetit() {
      DashboardStatsDTO dto = DashboardStatsDTO.builder()
          .totalContributionAmount(500.0)
          .build();

      assertThat(dto.getFormattedContributionAmount()).isEqualTo("500");
    }

    @Test
    @DisplayName("getFormattedContributionAmount - null")
    void testGetFormattedContributionAmountNull() {
      DashboardStatsDTO dto = new DashboardStatsDTO();

      assertThat(dto.getFormattedContributionAmount()).isEqualTo("0");
    }
  }

  @Nested
  @DisplayName("Tests getHasGrowth")
  class GetHasGrowthTests {

    @Test
    @DisplayName("getHasGrowth - croissance positive")
    void testGetHasGrowthPositif() {
      DashboardStatsDTO dto = DashboardStatsDTO.builder()
          .monthlyGrowth(5.5)
          .build();

      assertThat(dto.getHasGrowth()).isTrue();
    }

    @Test
    @DisplayName("getHasGrowth - croissance nulle")
    void testGetHasGrowthNul() {
      DashboardStatsDTO dto = DashboardStatsDTO.builder()
          .monthlyGrowth(0.0)
          .build();

      assertThat(dto.getHasGrowth()).isFalse();
    }

    @Test
    @DisplayName("getHasGrowth - croissance négative")
    void testGetHasGrowthNegatif() {
      DashboardStatsDTO dto = DashboardStatsDTO.builder()
          .monthlyGrowth(-2.5)
          .build();

      assertThat(dto.getHasGrowth()).isFalse();
    }

    @Test
    @DisplayName("getHasGrowth - null")
    void testGetHasGrowthNull() {
      DashboardStatsDTO dto = new DashboardStatsDTO();

      assertThat(dto.getHasGrowth()).isFalse();
    }
  }

  @Nested
  @DisplayName("Tests getIsHighEngagement")
  class GetIsHighEngagementTests {

    @Test
    @DisplayName("getIsHighEngagement - engagement élevé")
    void testGetIsHighEngagementEleve() {
      DashboardStatsDTO dto = DashboardStatsDTO.builder()
          .engagementRate(0.75)
          .build();

      assertThat(dto.getIsHighEngagement()).isTrue();
    }

    @Test
    @DisplayName("getIsHighEngagement - engagement à la limite")
    void testGetIsHighEngagementLimite() {
      DashboardStatsDTO dto = DashboardStatsDTO.builder()
          .engagementRate(0.7)
          .build();

      // 0.7 n'est pas > 0.7, donc false
      assertThat(dto.getIsHighEngagement()).isFalse();
    }

    @Test
    @DisplayName("getIsHighEngagement - engagement faible")
    void testGetIsHighEngagementFaible() {
      DashboardStatsDTO dto = DashboardStatsDTO.builder()
          .engagementRate(0.5)
          .build();

      assertThat(dto.getIsHighEngagement()).isFalse();
    }

    @Test
    @DisplayName("getIsHighEngagement - null")
    void testGetIsHighEngagementNull() {
      DashboardStatsDTO dto = new DashboardStatsDTO();

      assertThat(dto.getIsHighEngagement()).isFalse();
    }
  }

  @Nested
  @DisplayName("Tests getInactiveMembers")
  class GetInactiveMembersTests {

    @Test
    @DisplayName("getInactiveMembers - calcul correct")
    void testGetInactiveMembers() {
      DashboardStatsDTO dto = DashboardStatsDTO.builder()
          .totalMembers(100)
          .activeMembers(80)
          .build();

      assertThat(dto.getInactiveMembers()).isEqualTo(20.0);
    }

    @Test
    @DisplayName("getInactiveMembers - tous actifs")
    void testGetInactiveMembersTousActifs() {
      DashboardStatsDTO dto = DashboardStatsDTO.builder()
          .totalMembers(100)
          .activeMembers(100)
          .build();

      assertThat(dto.getInactiveMembers()).isEqualTo(0.0);
    }

    @Test
    @DisplayName("getInactiveMembers - null")
    void testGetInactiveMembersNull() {
      DashboardStatsDTO dto = new DashboardStatsDTO();

      assertThat(dto.getInactiveMembers()).isEqualTo(0.0);
    }
  }

  @Nested
  @DisplayName("Tests getActiveMemberPercentage")
  class GetActiveMemberPercentageTests {

    @Test
    @DisplayName("getActiveMemberPercentage - calcul correct")
    void testGetActiveMemberPercentage() {
      DashboardStatsDTO dto = DashboardStatsDTO.builder()
          .totalMembers(100)
          .activeMembers(80)
          .build();

      assertThat(dto.getActiveMemberPercentage()).isEqualTo(80.0);
    }

    @Test
    @DisplayName("getActiveMemberPercentage - tous actifs")
    void testGetActiveMemberPercentageTousActifs() {
      DashboardStatsDTO dto = DashboardStatsDTO.builder()
          .totalMembers(100)
          .activeMembers(100)
          .build();

      assertThat(dto.getActiveMemberPercentage()).isEqualTo(100.0);
    }

    @Test
    @DisplayName("getActiveMemberPercentage - totalMembers null")
    void testGetActiveMemberPercentageTotalNull() {
      DashboardStatsDTO dto = DashboardStatsDTO.builder()
          .activeMembers(80)
          .build();

      assertThat(dto.getActiveMemberPercentage()).isEqualTo(0.0);
    }

    @Test
    @DisplayName("getActiveMemberPercentage - totalMembers = 0")
    void testGetActiveMemberPercentageTotalZero() {
      DashboardStatsDTO dto = DashboardStatsDTO.builder()
          .totalMembers(0)
          .activeMembers(0)
          .build();

      assertThat(dto.getActiveMemberPercentage()).isEqualTo(0.0);
    }
  }

  @Nested
  @DisplayName("Tests getEngagementPercentage")
  class GetEngagementPercentageTests {

    @Test
    @DisplayName("getEngagementPercentage - calcul correct")
    void testGetEngagementPercentage() {
      DashboardStatsDTO dto = DashboardStatsDTO.builder()
          .engagementRate(0.75)
          .build();

      assertThat(dto.getEngagementPercentage()).isEqualTo(75.0);
    }

    @Test
    @DisplayName("getEngagementPercentage - null")
    void testGetEngagementPercentageNull() {
      DashboardStatsDTO dto = new DashboardStatsDTO();

      assertThat(dto.getEngagementPercentage()).isEqualTo(0.0);
    }
  }
}

