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

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

import java.math.BigDecimal;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.UUID;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Nested;
import org.junit.jupiter.api.Test;

/**
 * Tests unitaires complets pour AbonnementDTO.
 *
 * @author UnionFlow Team
 * @version 1.0
 * @since 2025-01-10
 */
@DisplayName("Tests AbonnementDTO")
class AbonnementDTOBasicTest {

  private AbonnementDTO abonnement;

  @BeforeEach
  void setUp() {
    abonnement = new AbonnementDTO();
  }

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

    @Test
    @DisplayName("Constructeur par défaut - Initialisation correcte")
    void testConstructeurParDefaut() {
      AbonnementDTO newAbonnement = new AbonnementDTO();

      assertThat(newAbonnement.getId()).isNotNull();
      assertThat(newAbonnement.getDateCreation()).isNotNull();
      assertThat(newAbonnement.isActif()).isTrue();
      assertThat(newAbonnement.getVersion()).isEqualTo(0L);
      assertThat(newAbonnement.getStatut()).isEqualTo("EN_ATTENTE_PAIEMENT");
      assertThat(newAbonnement.getDevise()).isEqualTo("XOF");
      assertThat(newAbonnement.getRenouvellementAutomatique()).isTrue();
      assertThat(newAbonnement.getPeriodeEssaiUtilisee()).isFalse();
      assertThat(newAbonnement.getSupportTechnique()).isTrue();
      assertThat(newAbonnement.getFonctionnalitesAvancees()).isFalse();
      assertThat(newAbonnement.getApiAccess()).isFalse();
      assertThat(newAbonnement.getRapportsPersonnalises()).isFalse();
      assertThat(newAbonnement.getIntegrationsTierces()).isFalse();
      assertThat(newAbonnement.getConnexionsCeMois()).isEqualTo(0);
      assertThat(newAbonnement.getAlertesActivees()).isTrue();
      assertThat(newAbonnement.getNotificationsEmail()).isTrue();
      assertThat(newAbonnement.getNotificationsSMS()).isFalse();
      assertThat(newAbonnement.getNumeroReference()).isNotNull();
      assertThat(newAbonnement.getNumeroReference()).matches("^ABO-\\d{4}-\\d{8}$");
    }

    @Test
    @DisplayName("Constructeur avec paramètres - Initialisation correcte")
    void testConstructeurAvecParametres() {
      UUID organisationId = UUID.randomUUID();
      String nomOrganisation = "Lions Club Dakar";
      String typeFormule = "PREMIUM";

      AbonnementDTO newAbonnement = new AbonnementDTO(organisationId, nomOrganisation, typeFormule);

      assertThat(newAbonnement.getOrganisationId()).isEqualTo(organisationId);
      assertThat(newAbonnement.getNomOrganisation()).isEqualTo(nomOrganisation);
      assertThat(newAbonnement.getTypeFormule()).isEqualTo(typeFormule);
      assertThat(newAbonnement.getStatut()).isEqualTo("EN_ATTENTE_PAIEMENT");
    }
  }

  @Nested
  @DisplayName("Tests Getters/Setters")
  class GettersSettersTests {

    @Test
    @DisplayName("Test tous les getters/setters - Partie 1")
    void testTousLesGettersSettersPart1() {
      // Données de test
      String numeroReference = "ABO-2025-12345678";
      UUID organisationId = UUID.randomUUID();
      String nomOrganisation = "Lions Club Test";
      UUID formulaireId = UUID.randomUUID();
      String codeFormule = "PREM001";
      String nomFormule = "Formule Premium";
      String typeFormule = "PREMIUM";
      String statut = "ACTIF";
      String typeAbonnement = "ANNUEL";
      LocalDate dateDebut = LocalDate.now();
      LocalDate dateFin = LocalDate.now().plusYears(1);
      LocalDate dateProchainePeriode = LocalDate.now().plusMonths(1);
      BigDecimal montant = new BigDecimal("500000.00");
      String devise = "XOF";
      BigDecimal remise = new BigDecimal("10.00");
      BigDecimal montantFinal = new BigDecimal("450000.00");

      // Test des setters
      abonnement.setNumeroReference(numeroReference);
      abonnement.setOrganisationId(organisationId);
      abonnement.setNomOrganisation(nomOrganisation);
      abonnement.setFormulaireId(formulaireId);
      abonnement.setCodeFormule(codeFormule);
      abonnement.setNomFormule(nomFormule);
      abonnement.setTypeFormule(typeFormule);
      abonnement.setStatut(statut);
      abonnement.setTypeAbonnement(typeAbonnement);
      abonnement.setDateDebut(dateDebut);
      abonnement.setDateFin(dateFin);
      abonnement.setDateProchainePeriode(dateProchainePeriode);
      abonnement.setMontant(montant);
      abonnement.setDevise(devise);
      abonnement.setRemise(remise);
      abonnement.setMontantFinal(montantFinal);

      // Test des getters
      assertThat(abonnement.getNumeroReference()).isEqualTo(numeroReference);
      assertThat(abonnement.getOrganisationId()).isEqualTo(organisationId);
      assertThat(abonnement.getNomOrganisation()).isEqualTo(nomOrganisation);
      assertThat(abonnement.getFormulaireId()).isEqualTo(formulaireId);
      assertThat(abonnement.getCodeFormule()).isEqualTo(codeFormule);
      assertThat(abonnement.getNomFormule()).isEqualTo(nomFormule);
      assertThat(abonnement.getTypeFormule()).isEqualTo(typeFormule);
      assertThat(abonnement.getStatut()).isEqualTo(statut);
      assertThat(abonnement.getTypeAbonnement()).isEqualTo(typeAbonnement);
      assertThat(abonnement.getDateDebut()).isEqualTo(dateDebut);
      assertThat(abonnement.getDateFin()).isEqualTo(dateFin);
      assertThat(abonnement.getDateProchainePeriode()).isEqualTo(dateProchainePeriode);
      assertThat(abonnement.getMontant()).isEqualTo(montant);
      assertThat(abonnement.getDevise()).isEqualTo(devise);
      assertThat(abonnement.getRemise()).isEqualTo(remise);
      assertThat(abonnement.getMontantFinal()).isEqualTo(montantFinal);
    }

    @Test
    @DisplayName("Test tous les getters/setters - Partie 2")
    void testTousLesGettersSettersPart2() {
      // Données de test
      Boolean renouvellementAutomatique = false;
      Boolean periodeEssaiUtilisee = true;
      LocalDate dateFinEssai = LocalDate.now().plusDays(30);
      Integer maxMembres = 100;
      Integer nombreMembresActuels = 75;
      BigDecimal espaceStockageGB = new BigDecimal("50.0");
      BigDecimal espaceStockageUtilise = new BigDecimal("25.5");
      Boolean supportTechnique = true;
      String niveauSupport = "PREMIUM";
      Boolean fonctionnalitesAvancees = true;
      Boolean apiAccess = true;
      Boolean rapportsPersonnalises = true;
      Boolean integrationsTierces = true;
      LocalDateTime dateDerniereUtilisation = LocalDateTime.now();
      Integer connexionsCeMois = 150;

      // Test des setters
      abonnement.setRenouvellementAutomatique(renouvellementAutomatique);
      abonnement.setPeriodeEssaiUtilisee(periodeEssaiUtilisee);
      abonnement.setDateFinEssai(dateFinEssai);
      abonnement.setMaxMembres(maxMembres);
      abonnement.setNombreMembresActuels(nombreMembresActuels);
      abonnement.setEspaceStockageGB(espaceStockageGB);
      abonnement.setEspaceStockageUtilise(espaceStockageUtilise);
      abonnement.setSupportTechnique(supportTechnique);
      abonnement.setNiveauSupport(niveauSupport);
      abonnement.setFonctionnalitesAvancees(fonctionnalitesAvancees);
      abonnement.setApiAccess(apiAccess);
      abonnement.setRapportsPersonnalises(rapportsPersonnalises);
      abonnement.setIntegrationsTierces(integrationsTierces);
      abonnement.setDateDerniereUtilisation(dateDerniereUtilisation);
      abonnement.setConnexionsCeMois(connexionsCeMois);

      // Test des getters
      assertThat(abonnement.getRenouvellementAutomatique()).isEqualTo(renouvellementAutomatique);
      assertThat(abonnement.getPeriodeEssaiUtilisee()).isEqualTo(periodeEssaiUtilisee);
      assertThat(abonnement.getDateFinEssai()).isEqualTo(dateFinEssai);
      assertThat(abonnement.getMaxMembres()).isEqualTo(maxMembres);
      assertThat(abonnement.getNombreMembresActuels()).isEqualTo(nombreMembresActuels);
      assertThat(abonnement.getEspaceStockageGB()).isEqualTo(espaceStockageGB);
      assertThat(abonnement.getEspaceStockageUtilise()).isEqualTo(espaceStockageUtilise);
      assertThat(abonnement.getSupportTechnique()).isEqualTo(supportTechnique);
      assertThat(abonnement.getNiveauSupport()).isEqualTo(niveauSupport);
      assertThat(abonnement.getFonctionnalitesAvancees()).isEqualTo(fonctionnalitesAvancees);
      assertThat(abonnement.getApiAccess()).isEqualTo(apiAccess);
      assertThat(abonnement.getRapportsPersonnalises()).isEqualTo(rapportsPersonnalises);
      assertThat(abonnement.getIntegrationsTierces()).isEqualTo(integrationsTierces);
      assertThat(abonnement.getDateDerniereUtilisation()).isEqualTo(dateDerniereUtilisation);
      assertThat(abonnement.getConnexionsCeMois()).isEqualTo(connexionsCeMois);
    }

    @Test
    @DisplayName("Test tous les getters/setters - Partie 3")
    void testTousLesGettersSettersPart3() {
      // Données de test
      UUID responsableId = UUID.randomUUID();
      String nomResponsable = "Jean Dupont";
      String emailResponsable = "jean.dupont@example.com";
      String telephoneResponsable = "+221701234567";
      String modePaiementPrefere = "WAVE_MONEY";
      String numeroPaiementMobile = "+221701234567";
      String historiquePaiements = "{\"paiements\": []}";
      String notes = "Notes sur l'abonnement";
      Boolean alertesActivees = false;
      Boolean notificationsEmail = false;
      Boolean notificationsSMS = true;
      LocalDateTime dateSuspension = LocalDateTime.now();
      String raisonSuspension = "Non-paiement";
      LocalDateTime dateAnnulation = LocalDateTime.now();
      String raisonAnnulation = "Demande client";

      // Test des setters
      abonnement.setResponsableId(responsableId);
      abonnement.setNomResponsable(nomResponsable);
      abonnement.setEmailResponsable(emailResponsable);
      abonnement.setTelephoneResponsable(telephoneResponsable);
      abonnement.setModePaiementPrefere(modePaiementPrefere);
      abonnement.setNumeroPaiementMobile(numeroPaiementMobile);
      abonnement.setHistoriquePaiements(historiquePaiements);
      abonnement.setNotes(notes);
      abonnement.setAlertesActivees(alertesActivees);
      abonnement.setNotificationsEmail(notificationsEmail);
      abonnement.setNotificationsSMS(notificationsSMS);
      abonnement.setDateSuspension(dateSuspension);
      abonnement.setRaisonSuspension(raisonSuspension);
      abonnement.setDateAnnulation(dateAnnulation);
      abonnement.setRaisonAnnulation(raisonAnnulation);

      // Test des getters
      assertThat(abonnement.getResponsableId()).isEqualTo(responsableId);
      assertThat(abonnement.getNomResponsable()).isEqualTo(nomResponsable);
      assertThat(abonnement.getEmailResponsable()).isEqualTo(emailResponsable);
      assertThat(abonnement.getTelephoneResponsable()).isEqualTo(telephoneResponsable);
      assertThat(abonnement.getModePaiementPrefere()).isEqualTo(modePaiementPrefere);
      assertThat(abonnement.getNumeroPaiementMobile()).isEqualTo(numeroPaiementMobile);
      assertThat(abonnement.getHistoriquePaiements()).isEqualTo(historiquePaiements);
      assertThat(abonnement.getNotes()).isEqualTo(notes);
      assertThat(abonnement.getAlertesActivees()).isEqualTo(alertesActivees);
      assertThat(abonnement.getNotificationsEmail()).isEqualTo(notificationsEmail);
      assertThat(abonnement.getNotificationsSMS()).isEqualTo(notificationsSMS);
      assertThat(abonnement.getDateSuspension()).isEqualTo(dateSuspension);
      assertThat(abonnement.getRaisonSuspension()).isEqualTo(raisonSuspension);
      assertThat(abonnement.getDateAnnulation()).isEqualTo(dateAnnulation);
      assertThat(abonnement.getRaisonAnnulation()).isEqualTo(raisonAnnulation);
    }
  }

  @Test
  @DisplayName("Test toString")
  void testToString() {
    abonnement.setNumeroReference("ABO-2025-12345678");
    abonnement.setNomOrganisation("Lions Club Test");
    abonnement.setStatut("ACTIF");

    String result = abonnement.toString();
    assertThat(result).isNotNull();
    assertThat(result).contains("AbonnementDTO");
  }
}
