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

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

import java.util.List;
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 PrioriteEvenement")
class PrioriteEvenementTest {

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

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

    @Test
    @DisplayName("Test toutes les valeurs enum")
    void testToutesValeurs() {
      PrioriteEvenement[] values = PrioriteEvenement.values();
      assertThat(values).hasSize(4);
      assertThat(values).containsExactly(
          PrioriteEvenement.CRITIQUE,
          PrioriteEvenement.HAUTE,
          PrioriteEvenement.NORMALE,
          PrioriteEvenement.BASSE);
    }

    @ParameterizedTest
    @EnumSource(PrioriteEvenement.class)
    @DisplayName("Test getters de base pour toutes les valeurs")
    void testGettersBase(PrioriteEvenement priorite) {
      assertThat(priorite.getLibelle()).isNotNull().isNotEmpty();
      assertThat(priorite.getCode()).isNotNull().isNotEmpty();
      assertThat(priorite.getNiveau()).isBetween(1, 4);
      assertThat(priorite.getDescription()).isNotNull().isNotEmpty();
      assertThat(priorite.getCouleur()).isNotNull().matches("#[0-9A-Fa-f]{6}");
      assertThat(priorite.getIcone()).isNotNull().isNotEmpty();
    }
  }

  @Nested
  @DisplayName("Tests isElevee")
  class IsEleveeTests {

    @ParameterizedTest
    @CsvSource({
        "CRITIQUE, true",
        "HAUTE, true",
        "NORMALE, false",
        "BASSE, false"
    })
    @DisplayName("isElevee - priorités élevées")
    void testIsElevee(PrioriteEvenement priorite, Boolean expected) {
      assertThat(priorite.isElevee()).isEqualTo(expected);
    }
  }

  @Nested
  @DisplayName("Tests isUrgente")
  class IsUrgenteTests {

    @ParameterizedTest
    @CsvSource({
        "CRITIQUE, true",
        "HAUTE, true",
        "NORMALE, false",
        "BASSE, false"
    })
    @DisplayName("isUrgente - priorités urgentes")
    void testIsUrgente(PrioriteEvenement priorite, Boolean expected) {
      assertThat(priorite.isUrgente()).isEqualTo(expected);
    }
  }

  @Nested
  @DisplayName("Tests isSuperieurA")
  class IsSuperieurATests {

    @Test
    @DisplayName("isSuperieurA - CRITIQUE supérieur à HAUTE")
    void testIsSuperieurACritiqueVersHaute() {
      assertThat(PrioriteEvenement.CRITIQUE.isSuperieurA(PrioriteEvenement.HAUTE)).isTrue();
    }

    @Test
    @DisplayName("isSuperieurA - HAUTE supérieur à NORMALE")
    void testIsSuperieurAHauteVersNormale() {
      assertThat(PrioriteEvenement.HAUTE.isSuperieurA(PrioriteEvenement.NORMALE)).isTrue();
    }

    @Test
    @DisplayName("isSuperieurA - NORMALE supérieur à BASSE")
    void testIsSuperieurANormaleVersBasse() {
      assertThat(PrioriteEvenement.NORMALE.isSuperieurA(PrioriteEvenement.BASSE)).isTrue();
    }

    @Test
    @DisplayName("isSuperieurA - BASSE n'est pas supérieur à CRITIQUE")
    void testIsSuperieurABasseVersCritique() {
      assertThat(PrioriteEvenement.BASSE.isSuperieurA(PrioriteEvenement.CRITIQUE)).isFalse();
    }

    @Test
    @DisplayName("isSuperieurA - même priorité retourne false")
    void testIsSuperieurAMemePriorite() {
      assertThat(PrioriteEvenement.CRITIQUE.isSuperieurA(PrioriteEvenement.CRITIQUE)).isFalse();
      assertThat(PrioriteEvenement.HAUTE.isSuperieurA(PrioriteEvenement.HAUTE)).isFalse();
      assertThat(PrioriteEvenement.NORMALE.isSuperieurA(PrioriteEvenement.NORMALE)).isFalse();
      assertThat(PrioriteEvenement.BASSE.isSuperieurA(PrioriteEvenement.BASSE)).isFalse();
    }

    @ParameterizedTest
    @CsvSource({
        "CRITIQUE, HAUTE, true",
        "CRITIQUE, NORMALE, true",
        "CRITIQUE, BASSE, true",
        "HAUTE, NORMALE, true",
        "HAUTE, BASSE, true",
        "NORMALE, BASSE, true",
        "HAUTE, CRITIQUE, false",
        "NORMALE, CRITIQUE, false",
        "NORMALE, HAUTE, false",
        "BASSE, CRITIQUE, false",
        "BASSE, HAUTE, false",
        "BASSE, NORMALE, false"
    })
    @DisplayName("isSuperieurA - toutes les combinaisons")
    void testIsSuperieurAToutesCombinaisons(
        PrioriteEvenement priorite1, PrioriteEvenement priorite2, boolean expected) {
      assertThat(priorite1.isSuperieurA(priorite2)).isEqualTo(expected);
    }
  }

  @Nested
  @DisplayName("Tests isNotificationImmediate et isEscaladeAutomatique")
  class IsNotificationImmediateEtEscaladeTests {

    @ParameterizedTest
    @CsvSource({
        "CRITIQUE, true, true",
        "HAUTE, true, false",
        "NORMALE, false, false",
        "BASSE, false, false"
    })
    @DisplayName("isNotificationImmediate et isEscaladeAutomatique - toutes les priorités")
    void testIsNotificationImmediateEtEscalade(
        PrioriteEvenement priorite, boolean notificationImmediate, boolean escaladeAutomatique) {
      assertThat(priorite.isNotificationImmediate()).isEqualTo(notificationImmediate);
      assertThat(priorite.isEscaladeAutomatique()).isEqualTo(escaladeAutomatique);
    }
  }

  @Nested
  @DisplayName("Tests méthodes statiques")
  class MethodesStatiquesTests {

    @Test
    @DisplayName("getPrioritesElevees - retourne les priorités élevées")
    void testGetPrioritesElevees() {
      List<PrioriteEvenement> priorites = PrioriteEvenement.getPrioritesElevees();
      assertThat(priorites).hasSize(2);
      assertThat(priorites).contains(PrioriteEvenement.CRITIQUE, PrioriteEvenement.HAUTE);
    }

    @Test
    @DisplayName("getPrioritesUrgentes - retourne les priorités urgentes")
    void testGetPrioritesUrgentes() {
      List<PrioriteEvenement> priorites = PrioriteEvenement.getPrioritesUrgentes();
      assertThat(priorites).hasSize(2);
      assertThat(priorites).contains(PrioriteEvenement.CRITIQUE, PrioriteEvenement.HAUTE);
    }

    @ParameterizedTest
    @CsvSource({
        "ASSEMBLEE_GENERALE, HAUTE",
        "REUNION_BUREAU, HAUTE",
        "ACTION_CARITATIVE, NORMALE",
        "FORMATION, NORMALE",
        "CONFERENCE, NORMALE",
        "CEREMONIE, NORMALE",
        "AUTRE, NORMALE",
        "ACTIVITE_SOCIALE, BASSE",
        "ATELIER, BASSE"
    })
    @DisplayName("determinerPriorite - tous les types d'événements")
    void testDeterminerPrioriteTousLesTypes(
        TypeEvenementMetier type, PrioriteEvenement expected) {
      assertThat(PrioriteEvenement.determinerPriorite(type)).isEqualTo(expected);
    }

    @Test
    @DisplayName("getDefaut - retourne NORMALE")
    void testGetDefaut() {
      assertThat(PrioriteEvenement.getDefaut()).isEqualTo(PrioriteEvenement.NORMALE);
    }
  }
}
