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

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

import java.time.LocalDateTime;
import java.util.List;
import java.util.UUID;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Nested;
import org.junit.jupiter.api.Test;
import dev.lions.unionflow.server.api.enums.analytics.FormatExport;
import dev.lions.unionflow.server.api.enums.analytics.PeriodeAnalyse;

/**
 * Tests unitaires pour ReportConfigDTO.
 * Couvre getNombreMetriques, getNombreSections, isPeriodePersonnalisee, isConfidentiel,
 * necessiteGeneration, getFrequenceTexte (toutes branches).
 *
 * @author UnionFlow Team
 * @version 1.0
 * @since 2026-02-21
 */
@DisplayName("Tests ReportConfigDTO")
class ReportConfigDTOTest {

  @Nested
  @DisplayName("getNombreMetriques")
  class GetNombreMetriques {

    @Test
    @DisplayName("retourne 0 quand metriques null")
    void testNull() {
      ReportConfigDTO dto = ReportConfigDTO.builder()
          .nom("Rapport")
          .typeRapport("executif")
          .periodeAnalyse(PeriodeAnalyse.CETTE_SEMAINE)
          .utilisateurCreateurId(UUID.randomUUID())
          .metriques(null)
          .formatExport(FormatExport.PDF).build();
      assertThat(dto.getNombreMetriques()).isEqualTo(0);
    }

    @Test
    @DisplayName("retourne la taille de metriques")
    void testSize() {
      ReportConfigDTO dto = ReportConfigDTO.builder()
          .nom("Rapport")
          .typeRapport("executif")
          .periodeAnalyse(PeriodeAnalyse.CETTE_SEMAINE)
          .utilisateurCreateurId(UUID.randomUUID())
          .metriques(List.of(
              ReportConfigDTO.MetriqueConfigDTO.builder().typeMetrique(dev.lions.unionflow.server.api.enums.analytics.TypeMetrique.NOMBRE_MEMBRES_ACTIFS).build(),
              ReportConfigDTO.MetriqueConfigDTO.builder().typeMetrique(dev.lions.unionflow.server.api.enums.analytics.TypeMetrique.TOTAL_COTISATIONS_COLLECTEES).build()))
          .formatExport(FormatExport.PDF).build();
      assertThat(dto.getNombreMetriques()).isEqualTo(2);
    }
  }

  @Nested
  @DisplayName("getNombreSections")
  class GetNombreSections {

    @Test
    @DisplayName("retourne 0 quand sections null")
    void testNull() {
      ReportConfigDTO dto = ReportConfigDTO.builder()
          .nom("Rapport")
          .typeRapport("executif")
          .periodeAnalyse(PeriodeAnalyse.CETTE_SEMAINE)
          .utilisateurCreateurId(UUID.randomUUID())
          .metriques(List.of())
          .sections(null)
          .formatExport(FormatExport.PDF).build();
      assertThat(dto.getNombreSections()).isEqualTo(0);
    }

    @Test
    @DisplayName("retourne la taille de sections")
    void testSize() {
      ReportConfigDTO dto = ReportConfigDTO.builder()
          .nom("Rapport")
          .typeRapport("executif")
          .periodeAnalyse(PeriodeAnalyse.CETTE_SEMAINE)
          .utilisateurCreateurId(UUID.randomUUID())
          .metriques(List.of())
          .sections(List.of(
              ReportConfigDTO.SectionRapportDTO.builder().nom("S1").typeSection("resume").build()))
          .formatExport(FormatExport.PDF).build();
      assertThat(dto.getNombreSections()).isEqualTo(1);
    }
  }

  @Nested
  @DisplayName("isPeriodePersonnalisee")
  class IsPeriodePersonnalisee {

    @Test
    @DisplayName("retourne true quand periodeAnalyse PERIODE_PERSONNALISEE")
    void testTrue() {
      ReportConfigDTO dto = ReportConfigDTO.builder()
          .nom("Rapport")
          .typeRapport("executif")
          .periodeAnalyse(PeriodeAnalyse.PERIODE_PERSONNALISEE)
          .utilisateurCreateurId(UUID.randomUUID())
          .metriques(List.of())
          .formatExport(FormatExport.PDF).build();
      assertThat(dto.isPeriodePersonnalisee()).isTrue();
    }

    @Test
    @DisplayName("retourne false pour autre période")
    void testFalse() {
      ReportConfigDTO dto = ReportConfigDTO.builder()
          .nom("Rapport")
          .typeRapport("executif")
          .periodeAnalyse(PeriodeAnalyse.CETTE_SEMAINE)
          .utilisateurCreateurId(UUID.randomUUID())
          .metriques(List.of())
          .formatExport(FormatExport.PDF).build();
      assertThat(dto.isPeriodePersonnalisee()).isFalse();
    }
  }

  @Nested
  @DisplayName("isConfidentiel")
  class IsConfidentiel {

    @Test
    @DisplayName("retourne false quand niveauConfidentialite null ou < 4")
    void testFalse() {
      ReportConfigDTO dto = ReportConfigDTO.builder()
          .nom("Rapport")
          .typeRapport("executif")
          .periodeAnalyse(PeriodeAnalyse.CETTE_SEMAINE)
          .utilisateurCreateurId(UUID.randomUUID())
          .metriques(List.of())
          .formatExport(FormatExport.PDF).build();
      assertThat(dto.isConfidentiel()).isFalse();
      dto.setNiveauConfidentialite(3);
      assertThat(dto.isConfidentiel()).isFalse();
    }

    @Test
    @DisplayName("retourne false quand niveauConfidentialite explicitement null")
    void testConfidentielNiveauNull() {
      ReportConfigDTO dto = ReportConfigDTO.builder()
          .nom("Rapport")
          .typeRapport("executif")
          .periodeAnalyse(PeriodeAnalyse.CETTE_SEMAINE)
          .utilisateurCreateurId(UUID.randomUUID())
          .metriques(List.of())
          .formatExport(FormatExport.PDF)
          .niveauConfidentialite(5).build();
      dto.setNiveauConfidentialite(null);
      assertThat(dto.isConfidentiel()).isFalse();
    }

    @Test
    @DisplayName("retourne true quand niveauConfidentialite >= 4")
    void testTrue() {
      ReportConfigDTO dto = ReportConfigDTO.builder()
          .nom("Rapport")
          .typeRapport("executif")
          .periodeAnalyse(PeriodeAnalyse.CETTE_SEMAINE)
          .utilisateurCreateurId(UUID.randomUUID())
          .metriques(List.of())
          .formatExport(FormatExport.PDF)
          .niveauConfidentialite(4).build();
      assertThat(dto.isConfidentiel()).isTrue();
      dto.setNiveauConfidentialite(5);
      assertThat(dto.isConfidentiel()).isTrue();
    }

    @Test
    @DisplayName("retourne false quand niveauConfidentialite non null mais < 4")
    void testNiveauNonNullInferieurA4() {
      ReportConfigDTO dto = ReportConfigDTO.builder()
          .nom("Rapport")
          .typeRapport("executif")
          .periodeAnalyse(PeriodeAnalyse.CETTE_SEMAINE)
          .utilisateurCreateurId(UUID.randomUUID())
          .metriques(List.of())
          .formatExport(FormatExport.PDF)
          .niveauConfidentialite(3).build();
      assertThat(dto.isConfidentiel()).isFalse();
    }
  }

  @Nested
  @DisplayName("necessiteGeneration")
  class NecessiteGeneration {

    @Test
    @DisplayName("retourne false quand rapportAutomatique false")
    void testNonAuto() {
      ReportConfigDTO dto = ReportConfigDTO.builder()
          .nom("Rapport")
          .typeRapport("executif")
          .periodeAnalyse(PeriodeAnalyse.CETTE_SEMAINE)
          .utilisateurCreateurId(UUID.randomUUID())
          .metriques(List.of())
          .formatExport(FormatExport.PDF)
          .rapportAutomatique(false)
          .prochaineGeneration(LocalDateTime.now().minusMinutes(1)).build();
      assertThat(dto.necessiteGeneration()).isFalse();
    }

    @Test
    @DisplayName("retourne false quand prochaineGeneration null")
    void testProchaineNull() {
      ReportConfigDTO dto = ReportConfigDTO.builder()
          .nom("Rapport")
          .typeRapport("executif")
          .periodeAnalyse(PeriodeAnalyse.CETTE_SEMAINE)
          .utilisateurCreateurId(UUID.randomUUID())
          .metriques(List.of())
          .formatExport(FormatExport.PDF)
          .rapportAutomatique(true)
          .prochaineGeneration(null).build();
      assertThat(dto.necessiteGeneration()).isFalse();
    }

    @Test
    @DisplayName("retourne true quand automatique et prochaineGeneration dans le passé")
    void testNecessite() {
      ReportConfigDTO dto = ReportConfigDTO.builder()
          .nom("Rapport")
          .typeRapport("executif")
          .periodeAnalyse(PeriodeAnalyse.CETTE_SEMAINE)
          .utilisateurCreateurId(UUID.randomUUID())
          .metriques(List.of())
          .formatExport(FormatExport.PDF)
          .rapportAutomatique(true)
          .prochaineGeneration(LocalDateTime.now().minusMinutes(10)).build();
      assertThat(dto.necessiteGeneration()).isTrue();
    }

    @Test
    @DisplayName("retourne false quand prochaineGeneration dans le futur")
    void testFutur() {
      ReportConfigDTO dto = ReportConfigDTO.builder()
          .nom("Rapport")
          .typeRapport("executif")
          .periodeAnalyse(PeriodeAnalyse.CETTE_SEMAINE)
          .utilisateurCreateurId(UUID.randomUUID())
          .metriques(List.of())
          .formatExport(FormatExport.PDF)
          .rapportAutomatique(true)
          .prochaineGeneration(LocalDateTime.now().plusHours(1)).build();
      assertThat(dto.necessiteGeneration()).isFalse();
    }
  }

  @Nested
  @DisplayName("getFrequenceTexte")
  class GetFrequenceTexte {

    @Test
    @DisplayName("retourne Manuelle quand frequenceGenerationHeures null")
    void testNull() {
      ReportConfigDTO dto = ReportConfigDTO.builder()
          .nom("Rapport")
          .typeRapport("executif")
          .periodeAnalyse(PeriodeAnalyse.CETTE_SEMAINE)
          .utilisateurCreateurId(UUID.randomUUID())
          .metriques(List.of())
          .formatExport(FormatExport.PDF).build();
      assertThat(dto.getFrequenceTexte()).isEqualTo("Manuelle");
    }

    @Test
    @DisplayName("retourne Toutes les heures pour 1")
    void test1() {
      ReportConfigDTO dto = ReportConfigDTO.builder()
          .nom("Rapport")
          .typeRapport("executif")
          .periodeAnalyse(PeriodeAnalyse.CETTE_SEMAINE)
          .utilisateurCreateurId(UUID.randomUUID())
          .metriques(List.of())
          .formatExport(FormatExport.PDF)
          .frequenceGenerationHeures(1).build();
      assertThat(dto.getFrequenceTexte()).isEqualTo("Toutes les heures");
    }

    @Test
    @DisplayName("retourne Quotidienne pour 24")
    void test24() {
      ReportConfigDTO dto = ReportConfigDTO.builder()
          .nom("Rapport")
          .typeRapport("executif")
          .periodeAnalyse(PeriodeAnalyse.CETTE_SEMAINE)
          .utilisateurCreateurId(UUID.randomUUID())
          .metriques(List.of())
          .formatExport(FormatExport.PDF)
          .frequenceGenerationHeures(24).build();
      assertThat(dto.getFrequenceTexte()).isEqualTo("Quotidienne");
    }

    @Test
    @DisplayName("retourne Hebdomadaire pour 168")
    void test168() {
      ReportConfigDTO dto = ReportConfigDTO.builder()
          .nom("Rapport")
          .typeRapport("executif")
          .periodeAnalyse(PeriodeAnalyse.CETTE_SEMAINE)
          .utilisateurCreateurId(UUID.randomUUID())
          .metriques(List.of())
          .formatExport(FormatExport.PDF)
          .frequenceGenerationHeures(168).build();
      assertThat(dto.getFrequenceTexte()).isEqualTo("Hebdomadaire");
    }

    @Test
    @DisplayName("retourne Mensuelle pour 720")
    void test720() {
      ReportConfigDTO dto = ReportConfigDTO.builder()
          .nom("Rapport")
          .typeRapport("executif")
          .periodeAnalyse(PeriodeAnalyse.CETTE_SEMAINE)
          .utilisateurCreateurId(UUID.randomUUID())
          .metriques(List.of())
          .formatExport(FormatExport.PDF)
          .frequenceGenerationHeures(720).build();
      assertThat(dto.getFrequenceTexte()).isEqualTo("Mensuelle");
    }

    @Test
    @DisplayName("retourne Toutes les X heures pour autre valeur")
    void testDefault() {
      ReportConfigDTO dto = ReportConfigDTO.builder()
          .nom("Rapport")
          .typeRapport("executif")
          .periodeAnalyse(PeriodeAnalyse.CETTE_SEMAINE)
          .utilisateurCreateurId(UUID.randomUUID())
          .metriques(List.of())
          .formatExport(FormatExport.PDF)
          .frequenceGenerationHeures(12).build();
      assertThat(dto.getFrequenceTexte()).isEqualTo("Toutes les 12 heures");
    }
  }
}
