package dev.lions.unionflow.server.api.enums.organisation;

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

import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Nested;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.CsvSource;
import org.junit.jupiter.params.provider.EnumSource;

@DisplayName("Tests pour TypeOrganisation")
class TypeOrganisationTest {

  @Test
  @DisplayName("Test de base - enum peut être utilisé")
  void testEnumUtilisable() {
    assertThat(TypeOrganisation.LIONS_CLUB).isNotNull();
    assertThat(TypeOrganisation.ORGANISATION_RELIGIEUSE).isNotNull();
  }

  @Nested
  @DisplayName("Tests des valeurs enum")
  class TestsValeursEnum {

    @Test
    @DisplayName("Test toutes les valeurs enum - couverture exhaustive")
    void testToutesValeurs() {
      TypeOrganisation[] values = TypeOrganisation.values();
      assertThat(values).hasSize(14);
      assertThat(values).containsExactly(
          TypeOrganisation.ASSOCIATION,
          TypeOrganisation.MUTUELLE_EPARGNE_CREDIT,
          TypeOrganisation.MUTUELLE_SANTE,
          TypeOrganisation.TONTINE,
          TypeOrganisation.ONG,
          TypeOrganisation.COOPERATIVE_AGRICOLE,
          TypeOrganisation.ASSOCIATION_PROFESSIONNELLE,
          TypeOrganisation.ASSOCIATION_COMMUNAUTAIRE,
          TypeOrganisation.ORGANISATION_RELIGIEUSE,
          TypeOrganisation.FEDERATION,
          TypeOrganisation.SYNDICAT,
          TypeOrganisation.LIONS_CLUB,
          TypeOrganisation.ROTARY_CLUB,
          TypeOrganisation.AUTRE);
    }

    @Test
    @DisplayName("Test valueOf - toutes les constantes")
    void testValueOf() {
      assertThat(TypeOrganisation.valueOf("ASSOCIATION")).isEqualTo(TypeOrganisation.ASSOCIATION);
      assertThat(TypeOrganisation.valueOf("MUTUELLE_EPARGNE_CREDIT")).isEqualTo(TypeOrganisation.MUTUELLE_EPARGNE_CREDIT);
      assertThat(TypeOrganisation.valueOf("MUTUELLE_SANTE")).isEqualTo(TypeOrganisation.MUTUELLE_SANTE);
      assertThat(TypeOrganisation.valueOf("TONTINE")).isEqualTo(TypeOrganisation.TONTINE);
      assertThat(TypeOrganisation.valueOf("ONG")).isEqualTo(TypeOrganisation.ONG);
      assertThat(TypeOrganisation.valueOf("COOPERATIVE_AGRICOLE")).isEqualTo(TypeOrganisation.COOPERATIVE_AGRICOLE);
      assertThat(TypeOrganisation.valueOf("ASSOCIATION_PROFESSIONNELLE")).isEqualTo(TypeOrganisation.ASSOCIATION_PROFESSIONNELLE);
      assertThat(TypeOrganisation.valueOf("ASSOCIATION_COMMUNAUTAIRE")).isEqualTo(TypeOrganisation.ASSOCIATION_COMMUNAUTAIRE);
      assertThat(TypeOrganisation.valueOf("ORGANISATION_RELIGIEUSE")).isEqualTo(TypeOrganisation.ORGANISATION_RELIGIEUSE);
      assertThat(TypeOrganisation.valueOf("FEDERATION")).isEqualTo(TypeOrganisation.FEDERATION);
      assertThat(TypeOrganisation.valueOf("SYNDICAT")).isEqualTo(TypeOrganisation.SYNDICAT);
      assertThat(TypeOrganisation.valueOf("LIONS_CLUB")).isEqualTo(TypeOrganisation.LIONS_CLUB);
      assertThat(TypeOrganisation.valueOf("ROTARY_CLUB")).isEqualTo(TypeOrganisation.ROTARY_CLUB);
      assertThat(TypeOrganisation.valueOf("AUTRE")).isEqualTo(TypeOrganisation.AUTRE);

      assertThatThrownBy(() -> TypeOrganisation.valueOf("INEXISTANT"))
          .isInstanceOf(IllegalArgumentException.class);
    }

    @ParameterizedTest
    @EnumSource(TypeOrganisation.class)
    @DisplayName("Test getLibelle pour toutes les valeurs - non null et non vide")
    void testGetLibelle(TypeOrganisation type) {
      assertThat(type.getLibelle()).isNotNull().isNotEmpty();
    }

    @ParameterizedTest
    @CsvSource({
        "LIONS_CLUB, Lions Club",
        "ASSOCIATION, Association",
        "ONG, ONG / Association humanitaire",
        "ORGANISATION_RELIGIEUSE, Organisation religieuse",
        "FEDERATION, Fédération / Union d'associations",
        "AUTRE, Autre"
    })
    @DisplayName("Test getLibelle avec valeurs exactes")
    void testGetLibelleValeursExactes(String name, String expectedLibelle) {
      assertThat(TypeOrganisation.valueOf(name).getLibelle()).isEqualTo(expectedLibelle);
    }

    @Test
    @DisplayName("Test name() pour toutes les constantes")
    void testOrdinalEtName() {
      assertThat(TypeOrganisation.ASSOCIATION.name()).isEqualTo("ASSOCIATION");
      assertThat(TypeOrganisation.LIONS_CLUB.name()).isEqualTo("LIONS_CLUB");
      assertThat(TypeOrganisation.ORGANISATION_RELIGIEUSE.name()).isEqualTo("ORGANISATION_RELIGIEUSE");
      assertThat(TypeOrganisation.MUTUELLE_SANTE.name()).isEqualTo("MUTUELLE_SANTE");
      assertThat(TypeOrganisation.ONG.name()).isEqualTo("ONG");
      assertThat(TypeOrganisation.AUTRE.name()).isEqualTo("AUTRE");
    }
  }
}

