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

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;

/**
 * Tests unitaires pour StatutAide.
 *
 * @author UnionFlow Team
 * @version 1.0
 * @since 2025-12-09
 */
@DisplayName("Tests StatutAide")
class StatutAideTest {

  @Test
  @DisplayName("Tous les statuts doivent avoir un libellé")
  void testTousLesStatutsOntLibelle() {
    for (StatutAide statut : StatutAide.values()) {
      assertThat(statut.getLibelle()).isNotNull().isNotBlank();
    }
  }

  @Test
  @DisplayName("Tous les statuts doivent avoir un code")
  void testTousLesStatutsOntCode() {
    for (StatutAide statut : StatutAide.values()) {
      assertThat(statut.getCode()).isNotNull().isNotBlank();
    }
  }

  @Nested
  @DisplayName("Tests isSucces")
  class IsSuccesTests {

    @Test
    @DisplayName("isSucces doit retourner true pour VERSEE, LIVREE, TERMINEE")
    void testIsSucces() {
      assertThat(StatutAide.VERSEE.isSucces()).isTrue();
      assertThat(StatutAide.LIVREE.isSucces()).isTrue();
      assertThat(StatutAide.TERMINEE.isSucces()).isTrue();

      assertThat(StatutAide.APPROUVEE.isSucces()).isFalse();
      assertThat(StatutAide.REJETEE.isSucces()).isFalse();
      assertThat(StatutAide.EN_ATTENTE.isSucces()).isFalse();
    }
  }

  @Nested
  @DisplayName("Tests isEnCours")
  class IsEnCoursTests {

    @Test
    @DisplayName("isEnCours doit retourner true pour les statuts en cours")
    void testIsEnCours() {
      assertThat(StatutAide.EN_COURS_EVALUATION.isEnCours()).isTrue();
      assertThat(StatutAide.EN_COURS_TRAITEMENT.isEnCours()).isTrue();
      assertThat(StatutAide.EN_COURS_VERSEMENT.isEnCours()).isTrue();

      assertThat(StatutAide.EN_ATTENTE.isEnCours()).isFalse();
      assertThat(StatutAide.APPROUVEE.isEnCours()).isFalse();
      assertThat(StatutAide.TERMINEE.isEnCours()).isFalse();
    }
  }

  @Nested
  @DisplayName("Tests permetModification")
  class PermetModificationTests {

    @Test
    @DisplayName("permetModification doit retourner true pour BROUILLON et INFORMATIONS_REQUISES")
    void testPermetModification() {
      assertThat(StatutAide.BROUILLON.permetModification()).isTrue();
      assertThat(StatutAide.INFORMATIONS_REQUISES.permetModification()).isTrue();

      assertThat(StatutAide.EN_ATTENTE.permetModification()).isFalse();
      assertThat(StatutAide.APPROUVEE.permetModification()).isFalse();
      assertThat(StatutAide.TERMINEE.permetModification()).isFalse();
    }
  }

  @Nested
  @DisplayName("Tests permetAnnulation")
  class PermetAnnulationTests {

    @Test
    @DisplayName("permetAnnulation doit retourner false pour les statuts finaux et ANNULEE")
    void testPermetAnnulation() {
      assertThat(StatutAide.ANNULEE.permetAnnulation()).isFalse();
      assertThat(StatutAide.TERMINEE.permetAnnulation()).isFalse();
      assertThat(StatutAide.VERSEE.permetAnnulation()).isFalse();
      assertThat(StatutAide.REJETEE.permetAnnulation()).isFalse();
      assertThat(StatutAide.EXPIREE.permetAnnulation()).isFalse();
      assertThat(StatutAide.CLOTUREE.permetAnnulation()).isFalse();

      assertThat(StatutAide.BROUILLON.permetAnnulation()).isTrue();
      assertThat(StatutAide.EN_ATTENTE.permetAnnulation()).isTrue();
      assertThat(StatutAide.EN_COURS_EVALUATION.permetAnnulation()).isTrue();
      assertThat(StatutAide.INFORMATIONS_REQUISES.permetAnnulation()).isTrue();
      assertThat(StatutAide.SUSPENDUE.permetAnnulation()).isTrue();
    }
  }

  @Nested
  @DisplayName("Tests getStatutsFinaux")
  class GetStatutsFinauxTests {

    @Test
    @DisplayName("getStatutsFinaux doit retourner tous les statuts finaux")
    void testGetStatutsFinaux() {
      List<StatutAide> statutsFinaux = StatutAide.getStatutsFinaux();

      assertThat(statutsFinaux).isNotEmpty();
      assertThat(statutsFinaux).contains(StatutAide.APPROUVEE);
      assertThat(statutsFinaux).contains(StatutAide.APPROUVEE_PARTIELLEMENT);
      assertThat(statutsFinaux).contains(StatutAide.REJETEE);
      assertThat(statutsFinaux).contains(StatutAide.VERSEE);
      assertThat(statutsFinaux).contains(StatutAide.LIVREE);
      assertThat(statutsFinaux).contains(StatutAide.TERMINEE);
      assertThat(statutsFinaux).contains(StatutAide.ANNULEE);
      assertThat(statutsFinaux).contains(StatutAide.EXPIREE);
      assertThat(statutsFinaux).contains(StatutAide.CLOTUREE);

      assertThat(statutsFinaux).doesNotContain(StatutAide.BROUILLON);
      assertThat(statutsFinaux).doesNotContain(StatutAide.EN_ATTENTE);
    }
  }

  @Nested
  @DisplayName("Tests getStatutsEchec")
  class GetStatutsEchecTests {

    @Test
    @DisplayName("getStatutsEchec doit retourner tous les statuts d'échec")
    void testGetStatutsEchec() {
      List<StatutAide> statutsEchec = StatutAide.getStatutsEchec();

      assertThat(statutsEchec).isNotEmpty();
      assertThat(statutsEchec).contains(StatutAide.REJETEE);
      assertThat(statutsEchec).contains(StatutAide.ANNULEE);
      assertThat(statutsEchec).contains(StatutAide.EXPIREE);

      assertThat(statutsEchec).doesNotContain(StatutAide.VERSEE);
      assertThat(statutsEchec).doesNotContain(StatutAide.TERMINEE);
    }
  }

  @Nested
  @DisplayName("Tests getStatutsSucces")
  class GetStatutsSuccesTests {

    @Test
    @DisplayName("getStatutsSucces doit retourner tous les statuts de succès")
    void testGetStatutsSucces() {
      List<StatutAide> statutsSucces = StatutAide.getStatutsSucces();

      assertThat(statutsSucces).isNotEmpty();
      assertThat(statutsSucces).contains(StatutAide.VERSEE);
      assertThat(statutsSucces).contains(StatutAide.LIVREE);
      assertThat(statutsSucces).contains(StatutAide.TERMINEE);

      assertThat(statutsSucces).doesNotContain(StatutAide.REJETEE);
      assertThat(statutsSucces).doesNotContain(StatutAide.APPROUVEE);
    }
  }

  @Nested
  @DisplayName("Tests getStatutsEnCours")
  class GetStatutsEnCoursTests {

    @Test
    @DisplayName("getStatutsEnCours doit retourner tous les statuts en cours")
    void testGetStatutsEnCours() {
      List<StatutAide> statutsEnCours = StatutAide.getStatutsEnCours();

      assertThat(statutsEnCours).isNotEmpty();
      assertThat(statutsEnCours).contains(StatutAide.EN_COURS_EVALUATION);
      assertThat(statutsEnCours).contains(StatutAide.EN_COURS_TRAITEMENT);
      assertThat(statutsEnCours).contains(StatutAide.EN_COURS_VERSEMENT);

      assertThat(statutsEnCours).doesNotContain(StatutAide.EN_ATTENTE);
      assertThat(statutsEnCours).doesNotContain(StatutAide.APPROUVEE);
    }
  }

  @Nested
  @DisplayName("Tests peutTransitionnerVers")
  class PeutTransitionnerVersTests {

    @Test
    @DisplayName("peutTransitionnerVers doit retourner false si même statut")
    void testMemeStatut() {
      assertThat(StatutAide.BROUILLON.peutTransitionnerVers(StatutAide.BROUILLON)).isFalse();
      assertThat(StatutAide.EN_ATTENTE.peutTransitionnerVers(StatutAide.EN_ATTENTE)).isFalse();
    }

    @Test
    @DisplayName("peutTransitionnerVers - BROUILLON peut aller vers SOUMISE ou ANNULEE")
    void testBrouillon() {
      assertThat(StatutAide.BROUILLON.peutTransitionnerVers(StatutAide.SOUMISE)).isTrue();
      assertThat(StatutAide.BROUILLON.peutTransitionnerVers(StatutAide.ANNULEE)).isTrue();
      assertThat(StatutAide.BROUILLON.peutTransitionnerVers(StatutAide.EN_ATTENTE)).isFalse();
    }

    @Test
    @DisplayName("peutTransitionnerVers - SOUMISE peut aller vers EN_ATTENTE ou ANNULEE")
    void testSoumise() {
      assertThat(StatutAide.SOUMISE.peutTransitionnerVers(StatutAide.EN_ATTENTE)).isTrue();
      assertThat(StatutAide.SOUMISE.peutTransitionnerVers(StatutAide.ANNULEE)).isTrue();
      assertThat(StatutAide.SOUMISE.peutTransitionnerVers(StatutAide.APPROUVEE)).isFalse();
    }

    @Test
    @DisplayName("peutTransitionnerVers - EN_ATTENTE peut aller vers EN_COURS_EVALUATION ou ANNULEE")
    void testEnAttente() {
      assertThat(StatutAide.EN_ATTENTE.peutTransitionnerVers(StatutAide.EN_COURS_EVALUATION))
          .isTrue();
      assertThat(StatutAide.EN_ATTENTE.peutTransitionnerVers(StatutAide.ANNULEE)).isTrue();
      assertThat(StatutAide.EN_ATTENTE.peutTransitionnerVers(StatutAide.APPROUVEE)).isFalse();
    }

    @Test
    @DisplayName("peutTransitionnerVers - EN_COURS_EVALUATION peut aller vers plusieurs statuts")
    void testEnCoursEvaluation() {
      assertThat(StatutAide.EN_COURS_EVALUATION.peutTransitionnerVers(StatutAide.APPROUVEE))
          .isTrue();
      assertThat(
              StatutAide.EN_COURS_EVALUATION.peutTransitionnerVers(StatutAide.APPROUVEE_PARTIELLEMENT))
          .isTrue();
      assertThat(StatutAide.EN_COURS_EVALUATION.peutTransitionnerVers(StatutAide.REJETEE)).isTrue();
      assertThat(
              StatutAide.EN_COURS_EVALUATION.peutTransitionnerVers(StatutAide.INFORMATIONS_REQUISES))
          .isTrue();
      assertThat(StatutAide.EN_COURS_EVALUATION.peutTransitionnerVers(StatutAide.SUSPENDUE))
          .isTrue();
      assertThat(StatutAide.EN_COURS_EVALUATION.peutTransitionnerVers(StatutAide.TERMINEE))
          .isFalse();
    }

    @Test
    @DisplayName("peutTransitionnerVers - INFORMATIONS_REQUISES peut aller vers EN_COURS_EVALUATION ou ANNULEE")
    void testInformationsRequises() {
      assertThat(
              StatutAide.INFORMATIONS_REQUISES.peutTransitionnerVers(StatutAide.EN_COURS_EVALUATION))
          .isTrue();
      assertThat(StatutAide.INFORMATIONS_REQUISES.peutTransitionnerVers(StatutAide.ANNULEE))
          .isTrue();
      assertThat(StatutAide.INFORMATIONS_REQUISES.peutTransitionnerVers(StatutAide.APPROUVEE))
          .isFalse();
    }

    @Test
    @DisplayName("peutTransitionnerVers - APPROUVEE peut aller vers EN_COURS_TRAITEMENT ou SUSPENDUE")
    void testApprouvee() {
      assertThat(StatutAide.APPROUVEE.peutTransitionnerVers(StatutAide.EN_COURS_TRAITEMENT))
          .isTrue();
      assertThat(StatutAide.APPROUVEE.peutTransitionnerVers(StatutAide.SUSPENDUE)).isTrue();
      assertThat(StatutAide.APPROUVEE.peutTransitionnerVers(StatutAide.VERSEE)).isFalse();
    }

    @Test
    @DisplayName("peutTransitionnerVers - EN_COURS_TRAITEMENT peut aller vers plusieurs statuts")
    void testEnCoursTraitement() {
      assertThat(StatutAide.EN_COURS_TRAITEMENT.peutTransitionnerVers(StatutAide.EN_COURS_VERSEMENT))
          .isTrue();
      assertThat(StatutAide.EN_COURS_TRAITEMENT.peutTransitionnerVers(StatutAide.LIVREE)).isTrue();
      assertThat(StatutAide.EN_COURS_TRAITEMENT.peutTransitionnerVers(StatutAide.TERMINEE))
          .isTrue();
      assertThat(StatutAide.EN_COURS_TRAITEMENT.peutTransitionnerVers(StatutAide.SUSPENDUE))
          .isTrue();
      assertThat(StatutAide.EN_COURS_TRAITEMENT.peutTransitionnerVers(StatutAide.APPROUVEE))
          .isFalse();
    }

    @Test
    @DisplayName("peutTransitionnerVers - EN_COURS_VERSEMENT peut aller vers VERSEE ou SUSPENDUE")
    void testEnCoursVersement() {
      assertThat(StatutAide.EN_COURS_VERSEMENT.peutTransitionnerVers(StatutAide.VERSEE)).isTrue();
      assertThat(StatutAide.EN_COURS_VERSEMENT.peutTransitionnerVers(StatutAide.SUSPENDUE))
          .isTrue();
      assertThat(StatutAide.EN_COURS_VERSEMENT.peutTransitionnerVers(StatutAide.TERMINEE))
          .isFalse();
    }

    @Test
    @DisplayName("peutTransitionnerVers - SUSPENDUE peut aller vers EN_COURS_EVALUATION ou ANNULEE")
    void testSuspendue() {
      assertThat(StatutAide.SUSPENDUE.peutTransitionnerVers(StatutAide.EN_COURS_EVALUATION))
          .isTrue();
      assertThat(StatutAide.SUSPENDUE.peutTransitionnerVers(StatutAide.ANNULEE)).isTrue();
      assertThat(StatutAide.SUSPENDUE.peutTransitionnerVers(StatutAide.APPROUVEE)).isFalse();
    }

    @Test
    @DisplayName("peutTransitionnerVers - Les statuts finaux ne peuvent pas transitionner (sauf APPROUVEE)")
    void testStatutsFinaux() {
      // Les statuts finaux (sauf APPROUVEE et APPROUVEE_PARTIELLEMENT) ne peuvent pas transitionner
      // car le switch retourne false par défaut
      assertThat(StatutAide.TERMINEE.peutTransitionnerVers(StatutAide.EN_SUIVI)).isFalse();
      assertThat(StatutAide.VERSEE.peutTransitionnerVers(StatutAide.EN_SUIVI)).isFalse();
      assertThat(StatutAide.TERMINEE.peutTransitionnerVers(StatutAide.APPROUVEE)).isFalse();
      assertThat(StatutAide.VERSEE.peutTransitionnerVers(StatutAide.APPROUVEE)).isFalse();
      assertThat(StatutAide.REJETEE.peutTransitionnerVers(StatutAide.EN_SUIVI)).isFalse();
      assertThat(StatutAide.ANNULEE.peutTransitionnerVers(StatutAide.EN_SUIVI)).isFalse();

      // APPROUVEE et APPROUVEE_PARTIELLEMENT peuvent transitionner vers EN_COURS_TRAITEMENT ou SUSPENDUE
      assertThat(StatutAide.APPROUVEE.peutTransitionnerVers(StatutAide.EN_COURS_TRAITEMENT))
          .isTrue();
      assertThat(StatutAide.APPROUVEE_PARTIELLEMENT.peutTransitionnerVers(StatutAide.EN_COURS_TRAITEMENT))
          .isTrue();
      assertThat(StatutAide.APPROUVEE.peutTransitionnerVers(StatutAide.SUSPENDUE)).isTrue();
    }
  }

  @Nested
  @DisplayName("Tests getNiveauPriorite")
  class GetNiveauPrioriteTests {

    @Test
    @DisplayName("getNiveauPriorite doit retourner le bon niveau")
    void testGetNiveauPriorite() {
      assertThat(StatutAide.INFORMATIONS_REQUISES.getNiveauPriorite()).isEqualTo(1);
      assertThat(StatutAide.EN_COURS_EVALUATION.getNiveauPriorite()).isEqualTo(2);
      assertThat(StatutAide.EN_COURS_TRAITEMENT.getNiveauPriorite()).isEqualTo(2);
      assertThat(StatutAide.EN_COURS_VERSEMENT.getNiveauPriorite()).isEqualTo(2);
      assertThat(StatutAide.APPROUVEE.getNiveauPriorite()).isEqualTo(3);
      assertThat(StatutAide.APPROUVEE_PARTIELLEMENT.getNiveauPriorite()).isEqualTo(3);
      assertThat(StatutAide.EN_ATTENTE.getNiveauPriorite()).isEqualTo(4);
      assertThat(StatutAide.SOUMISE.getNiveauPriorite()).isEqualTo(4);
      assertThat(StatutAide.SUSPENDUE.getNiveauPriorite()).isEqualTo(5);
      assertThat(StatutAide.BROUILLON.getNiveauPriorite()).isEqualTo(6);
      assertThat(StatutAide.EN_SUIVI.getNiveauPriorite()).isEqualTo(7);
      assertThat(StatutAide.TERMINEE.getNiveauPriorite()).isEqualTo(8);
      assertThat(StatutAide.VERSEE.getNiveauPriorite()).isEqualTo(8);
    }
  }
}
