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

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

import java.math.BigDecimal;
import java.time.LocalDate;
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.formuleabonnement.StatutFormule;
import dev.lions.unionflow.server.api.enums.formuleabonnement.TypeFormule;

/**
 * Tests unitaires pour FormuleAbonnementResponse.
 * Couvre toutes les branches : isActive, isInactive, isArchivee, isValide, getEconomieAnnuelle,
 * getPourcentageEconomieAnnuelle (y compris coutMensuelAnnuel <= 0), hasPeriodeEssai, hasFormation,
 * isMiseEnAvant, getBadge (4 branches), getScoreFonctionnalites, getCssClass (type null + switch).
 *
 * @author UnionFlow Team
 * @version 1.0
 * @since 2026-02-21
 */
@DisplayName("Tests FormuleAbonnementResponse")
class FormuleAbonnementResponseTest {

  @Nested
  @DisplayName("isValide")
  class IsValide {

    @Test
    @DisplayName("false quand statut pas ACTIVE")
    void testNonActive() {
      FormuleAbonnementResponse r = FormuleAbonnementResponse.builder()
          .statut(StatutFormule.INACTIVE)
          .build();
      assertThat(r.isValide()).isFalse();
    }

    @Test
    @DisplayName("false quand dateDebutValidite dans le futur")
    void testDateDebutFuture() {
      FormuleAbonnementResponse r = FormuleAbonnementResponse.builder()
          .statut(StatutFormule.ACTIVE)
          .dateDebutValidite(LocalDate.now().plusDays(1))
          .build();
      assertThat(r.isValide()).isFalse();
    }

    @Test
    @DisplayName("false quand dateFinValidite dans le passé")
    void testDateFinPassee() {
      FormuleAbonnementResponse r = FormuleAbonnementResponse.builder()
          .statut(StatutFormule.ACTIVE)
          .dateFinValidite(LocalDate.now().minusDays(1))
          .build();
      assertThat(r.isValide()).isFalse();
    }

    @Test
    @DisplayName("true quand ACTIVE et dates OK")
    void testValide() {
      FormuleAbonnementResponse r = FormuleAbonnementResponse.builder()
          .statut(StatutFormule.ACTIVE)
          .dateDebutValidite(LocalDate.now().minusDays(1))
          .dateFinValidite(LocalDate.now().plusDays(1))
          .build();
      assertThat(r.isValide()).isTrue();
    }
  }

  @Nested
  @DisplayName("getPourcentageEconomieAnnuelle")
  class GetPourcentageEconomieAnnuelle {

    @Test
    @DisplayName("retourne 0 quand prixMensuel null")
    void testPrixMensuelNull() {
      FormuleAbonnementResponse r = FormuleAbonnementResponse.builder().prixAnnuel(BigDecimal.TEN).build();
      assertThat(r.getPourcentageEconomieAnnuelle()).isEqualTo(0);
    }

    @Test
    @DisplayName("retourne 0 quand coutMensuelAnnuel <= 0")
    void testCoutMensuelZero() {
      FormuleAbonnementResponse r = FormuleAbonnementResponse.builder()
          .prixMensuel(BigDecimal.ZERO)
          .prixAnnuel(BigDecimal.ZERO)
          .build();
      assertThat(r.getPourcentageEconomieAnnuelle()).isEqualTo(0);
    }

    @Test
    @DisplayName("calcule pourcentage quand économie positive")
    void testPourcentagePositif() {
      FormuleAbonnementResponse r = FormuleAbonnementResponse.builder()
          .prixMensuel(BigDecimal.valueOf(10))
          .prixAnnuel(BigDecimal.valueOf(100))
          .build();
      assertThat(r.getPourcentageEconomieAnnuelle()).isGreaterThan(0);
    }
  }

  @Nested
  @DisplayName("getBadge")
  class GetBadge {

    @Test
    @DisplayName("POPULAIRE quand populaire true")
    void testPopulaire() {
      FormuleAbonnementResponse r = FormuleAbonnementResponse.builder()
          .populaire(true)
          .recommandee(false)
          .periodeEssaiJours(0)
          .build();
      assertThat(r.getBadge()).isEqualTo("POPULAIRE");
    }

    @Test
    @DisplayName("RECOMMANDÉE quand recommandee true et pas populaire")
    void testRecommandee() {
      FormuleAbonnementResponse r = FormuleAbonnementResponse.builder()
          .populaire(false)
          .recommandee(true)
          .periodeEssaiJours(0)
          .build();
      assertThat(r.getBadge()).isEqualTo("RECOMMANDÉE");
    }

    @Test
    @DisplayName("ESSAI GRATUIT quand periodeEssaiJours > 0 et pas populaire/recommandee")
    void testEssaiGratuit() {
      FormuleAbonnementResponse r = FormuleAbonnementResponse.builder()
          .populaire(false)
          .recommandee(false)
          .periodeEssaiJours(7)
          .build();
      assertThat(r.getBadge()).isEqualTo("ESSAI GRATUIT");
    }

    @Test
    @DisplayName("null quand aucun badge")
    void testAucunBadge() {
      FormuleAbonnementResponse r = FormuleAbonnementResponse.builder()
          .populaire(false)
          .recommandee(false)
          .periodeEssaiJours(0)
          .build();
      assertThat(r.getBadge()).isNull();
    }
  }

  @Nested
  @DisplayName("getScoreFonctionnalites")
  class GetScoreFonctionnalites {

    @Test
    @DisplayName("0 quand tous les booléens false")
    void testTousFalse() {
      FormuleAbonnementResponse r = FormuleAbonnementResponse.builder()
          .supportTechnique(false)
          .sauvegardeAutomatique(false)
          .fonctionnalitesAvancees(false)
          .apiAccess(false)
          .rapportsPersonnalises(false)
          .integrationsTierces(false)
          .multiLangues(false)
          .personnalisationInterface(false)
          .build();
      assertThat(r.getScoreFonctionnalites()).isEqualTo(0);
    }

    @Test
    @DisplayName("0 quand toutes les fonctionnalités sont null (aucune config)")
    void testToutesFonctionnalitesNull() {
      FormuleAbonnementResponse r = FormuleAbonnementResponse.builder().build();
      assertThat(r.getScoreFonctionnalites()).isEqualTo(0);
    }

    @Test
    @DisplayName("score > 0 quand au moins un true")
    void testAuMoinsUnTrue() {
      FormuleAbonnementResponse r = FormuleAbonnementResponse.builder()
          .supportTechnique(true)
          .sauvegardeAutomatique(false)
          .fonctionnalitesAvancees(false)
          .apiAccess(false)
          .rapportsPersonnalises(false)
          .integrationsTierces(false)
          .multiLangues(false)
          .personnalisationInterface(false)
          .build();
      assertThat(r.getScoreFonctionnalites()).isGreaterThan(0);
    }

    @Test
    @DisplayName("personnalisationInterface et multiLangues true augmentent le score")
    void testPersonnalisationEtMultiLangues() {
      FormuleAbonnementResponse r = FormuleAbonnementResponse.builder()
          .supportTechnique(false)
          .sauvegardeAutomatique(false)
          .fonctionnalitesAvancees(false)
          .apiAccess(false)
          .rapportsPersonnalises(false)
          .integrationsTierces(false)
          .multiLangues(true)
          .personnalisationInterface(true)
          .build();
      assertThat(r.getScoreFonctionnalites()).isGreaterThan(0);
    }
  }

  @Nested
  @DisplayName("getCssClass")
  class GetCssClass {

    @Test
    @DisplayName("formule-default quand type null")
    void testTypeNull() {
      FormuleAbonnementResponse r = FormuleAbonnementResponse.builder().type(null).build();
      assertThat(r.getCssClass()).isEqualTo("formule-default");
    }

    @Test
    @DisplayName("formule-basic pour BASIC")
    void testBasic() {
      FormuleAbonnementResponse r = FormuleAbonnementResponse.builder().type(TypeFormule.BASIC).build();
      assertThat(r.getCssClass()).isEqualTo("formule-basic");
    }

    @Test
    @DisplayName("formule-standard pour STANDARD")
    void testStandard() {
      FormuleAbonnementResponse r = FormuleAbonnementResponse.builder().type(TypeFormule.STANDARD).build();
      assertThat(r.getCssClass()).isEqualTo("formule-standard");
    }

    @Test
    @DisplayName("formule-premium pour PREMIUM")
    void testPremium() {
      FormuleAbonnementResponse r = FormuleAbonnementResponse.builder().type(TypeFormule.PREMIUM).build();
      assertThat(r.getCssClass()).isEqualTo("formule-premium");
    }

    @Test
    @DisplayName("formule-enterprise pour ENTERPRISE")
    void testEnterprise() {
      FormuleAbonnementResponse r = FormuleAbonnementResponse.builder().type(TypeFormule.ENTERPRISE).build();
      assertThat(r.getCssClass()).isEqualTo("formule-enterprise");
    }
  }

  @Nested
  @DisplayName("isActive, isInactive, isArchivee")
  class Statut {

    @Test
    @DisplayName("isActive true pour ACTIVE")
    void testActive() {
      FormuleAbonnementResponse r = FormuleAbonnementResponse.builder().statut(StatutFormule.ACTIVE).build();
      assertThat(r.isActive()).isTrue();
    }

    @Test
    @DisplayName("isInactive true pour INACTIVE")
    void testInactive() {
      FormuleAbonnementResponse r = FormuleAbonnementResponse.builder().statut(StatutFormule.INACTIVE).build();
      assertThat(r.isInactive()).isTrue();
    }

    @Test
    @DisplayName("isArchivee true pour ARCHIVEE")
    void testArchivee() {
      FormuleAbonnementResponse r = FormuleAbonnementResponse.builder().statut(StatutFormule.ARCHIVEE).build();
      assertThat(r.isArchivee()).isTrue();
    }
  }

  @Nested
  @DisplayName("hasPeriodeEssai, hasFormation, isMiseEnAvant")
  class AutresBranches {

    @Test
    @DisplayName("hasPeriodeEssai true quand periodeEssaiJours > 0")
    void testHasPeriodeEssai() {
      FormuleAbonnementResponse r = FormuleAbonnementResponse.builder().periodeEssaiJours(14).build();
      assertThat(r.hasPeriodeEssai()).isTrue();
    }

    @Test
    @DisplayName("hasFormation true quand formationIncluse et heuresFormation > 0")
    void testHasFormation() {
      FormuleAbonnementResponse r = FormuleAbonnementResponse.builder()
          .formationIncluse(true)
          .heuresFormation(10)
          .build();
      assertThat(r.hasFormation()).isTrue();
    }

    @Test
    @DisplayName("hasFormation false quand formationIncluse false")
    void testHasFormationFalse() {
      FormuleAbonnementResponse r = FormuleAbonnementResponse.builder()
          .formationIncluse(false)
          .heuresFormation(10)
          .build();
      assertThat(r.hasFormation()).isFalse();
    }

    @Test
    @DisplayName("hasFormation false quand heuresFormation null ou 0")
    void testHasFormationHeuresNullOuZero() {
      FormuleAbonnementResponse r = FormuleAbonnementResponse.builder()
          .formationIncluse(true)
          .heuresFormation(null)
          .build();
      assertThat(r.hasFormation()).isFalse();
      r.setHeuresFormation(0);
      assertThat(r.hasFormation()).isFalse();
    }

    @Test
    @DisplayName("isMiseEnAvant true quand populaire ou recommandee")
    void testMiseEnAvant() {
      FormuleAbonnementResponse r = FormuleAbonnementResponse.builder().populaire(true).build();
      assertThat(r.isMiseEnAvant()).isTrue();
      r.setPopulaire(false);
      r.setRecommandee(true);
      assertThat(r.isMiseEnAvant()).isTrue();
    }
  }
}
