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;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.CsvSource;
import org.junit.jupiter.params.provider.EnumSource;

@DisplayName("Tests pour StatutAide")
class StatutAideTest {

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

    @Test
    @DisplayName("Test toutes les valeurs enum")
    void testToutesValeurs() {
      StatutAide[] values = StatutAide.values();
      assertThat(values).hasSize(18);
    }

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

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

    @ParameterizedTest
    @CsvSource({
        "VERSEE, true",
        "LIVREE, true",
        "TERMINEE, true",
        "APPROUVEE, false",
        "REJETEE, false",
        "ANNULEE, false"
    })
    @DisplayName("isSucces - statuts de succès")
    void testIsSucces(StatutAide statut, Boolean expected) {
      assertThat(statut.isSucces()).isEqualTo(expected);
    }
  }

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

    @ParameterizedTest
    @CsvSource({
        "EN_COURS_EVALUATION, true",
        "EN_COURS_TRAITEMENT, true",
        "EN_COURS_VERSEMENT, true",
        "APPROUVEE, false",
        "TERMINEE, false"
    })
    @DisplayName("isEnCours - statuts en cours")
    void testIsEnCours(StatutAide statut, Boolean expected) {
      assertThat(statut.isEnCours()).isEqualTo(expected);
    }
  }

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

    @ParameterizedTest
    @CsvSource({
        "BROUILLON, true",
        "INFORMATIONS_REQUISES, true",
        "APPROUVEE, false",
        "TERMINEE, false"
    })
    @DisplayName("permetModification - statuts modifiables")
    void testPermetModification(StatutAide statut, Boolean expected) {
      assertThat(statut.permetModification()).isEqualTo(expected);
    }
  }

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

    @ParameterizedTest
    @CsvSource({
        "BROUILLON, true",
        "SOUMISE, true",
        "EN_ATTENTE, true",
        "TERMINEE, false",
        "ANNULEE, false"
    })
    @DisplayName("permetAnnulation - statuts annulables")
    void testPermetAnnulation(StatutAide statut, Boolean expected) {
      assertThat(statut.permetAnnulation()).isEqualTo(expected);
    }
  }

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

    @Test
    @DisplayName("peutTransitionnerVers - même statut retourne false")
    void testPeutTransitionnerVersMemeStatut() {
      for (StatutAide statut : StatutAide.values()) {
        assertThat(statut.peutTransitionnerVers(statut)).isFalse();
      }
    }

    @Test
    @DisplayName("peutTransitionnerVers - statut final vers autre statut")
    void testPeutTransitionnerVersStatutFinal() {
      // Statuts finaux (sauf APPROUVEE et APPROUVEE_PARTIELLEMENT) ne peuvent transitionner que vers EN_SUIVI
      // Mais comme ils ne sont pas dans le switch, ils tombent dans default -> false
      assertThat(StatutAide.TERMINEE.peutTransitionnerVers(StatutAide.APPROUVEE)).isFalse();
      assertThat(StatutAide.TERMINEE.peutTransitionnerVers(StatutAide.EN_SUIVI)).isFalse();
      assertThat(StatutAide.VERSEE.peutTransitionnerVers(StatutAide.EN_SUIVI)).isFalse();
      assertThat(StatutAide.LIVREE.peutTransitionnerVers(StatutAide.EN_SUIVI)).isFalse();
      assertThat(StatutAide.REJETEE.peutTransitionnerVers(StatutAide.EN_SUIVI)).isFalse();
      assertThat(StatutAide.ANNULEE.peutTransitionnerVers(StatutAide.EN_SUIVI)).isFalse();
      assertThat(StatutAide.EXPIREE.peutTransitionnerVers(StatutAide.EN_SUIVI)).isFalse();
      assertThat(StatutAide.CLOTUREE.peutTransitionnerVers(StatutAide.EN_SUIVI)).isFalse();
    }

    @Test
    @DisplayName("peutTransitionnerVers - condition estFinal avec APPROUVEE et APPROUVEE_PARTIELLEMENT")
    void testPeutTransitionnerVersConditionEstFinalAvecApprouvee() {
      // Test de la condition ligne 251-255 : estFinal && this != APPROUVEE && this != APPROUVEE_PARTIELLEMENT && nouveauStatut != EN_SUIVI
      // APPROUVEE est final mais peut transitionner vers EN_COURS_TRAITEMENT (exception)
      assertThat(StatutAide.APPROUVEE.peutTransitionnerVers(StatutAide.EN_COURS_TRAITEMENT)).isTrue();
      // APPROUVEE_PARTIELLEMENT est final mais peut transitionner vers EN_COURS_TRAITEMENT (exception)
      assertThat(StatutAide.APPROUVEE_PARTIELLEMENT.peutTransitionnerVers(StatutAide.EN_COURS_TRAITEMENT)).isTrue();
      // Autres statuts finaux ne peuvent pas transitionner vers autre chose que EN_SUIVI
      // Mais comme ils ne sont pas dans le switch, ils retournent false
      assertThat(StatutAide.TERMINEE.peutTransitionnerVers(StatutAide.APPROUVEE)).isFalse();
    }

    @Test
    @DisplayName("peutTransitionnerVers - toutes les branches de la condition estFinal")
    void testPeutTransitionnerVersToutesBranchesConditionEstFinal() {
      // Branche 1: estFinal == false (statut non final) - ne bloque pas
      assertThat(StatutAide.BROUILLON.peutTransitionnerVers(StatutAide.SOUMISE)).isTrue();
      
      // Branche 2: estFinal == true && this == APPROUVEE - ne bloque pas (exception)
      assertThat(StatutAide.APPROUVEE.peutTransitionnerVers(StatutAide.EN_COURS_TRAITEMENT)).isTrue();
      
      // Branche 3: estFinal == true && this == APPROUVEE_PARTIELLEMENT - ne bloque pas (exception)
      assertThat(StatutAide.APPROUVEE_PARTIELLEMENT.peutTransitionnerVers(StatutAide.EN_COURS_TRAITEMENT)).isTrue();
      
      // Branche 4: estFinal == true && this != APPROUVEE && this != APPROUVEE_PARTIELLEMENT && nouveauStatut == EN_SUIVI
      // La condition ne bloque pas, mais le switch retourne false (default)
      assertThat(StatutAide.TERMINEE.peutTransitionnerVers(StatutAide.EN_SUIVI)).isFalse();
      
      // Branche 5: estFinal == true && this != APPROUVEE && this != APPROUVEE_PARTIELLEMENT && nouveauStatut != EN_SUIVI
      // La condition bloque
      assertThat(StatutAide.TERMINEE.peutTransitionnerVers(StatutAide.APPROUVEE)).isFalse();
      assertThat(StatutAide.VERSEE.peutTransitionnerVers(StatutAide.APPROUVEE)).isFalse();
    }

    @Test
    @DisplayName("peutTransitionnerVers - BROUILLON - toutes les transitions")
    void testPeutTransitionnerVersBrouillon() {
      assertThat(StatutAide.BROUILLON.peutTransitionnerVers(StatutAide.SOUMISE)).isTrue();
      assertThat(StatutAide.BROUILLON.peutTransitionnerVers(StatutAide.ANNULEE)).isTrue();
      assertThat(StatutAide.BROUILLON.peutTransitionnerVers(StatutAide.EN_ATTENTE)).isFalse();
      assertThat(StatutAide.BROUILLON.peutTransitionnerVers(StatutAide.APPROUVEE)).isFalse();
    }

    @Test
    @DisplayName("peutTransitionnerVers - SOUMISE - toutes les transitions")
    void testPeutTransitionnerVersSoumise() {
      assertThat(StatutAide.SOUMISE.peutTransitionnerVers(StatutAide.EN_ATTENTE)).isTrue();
      assertThat(StatutAide.SOUMISE.peutTransitionnerVers(StatutAide.ANNULEE)).isTrue();
      assertThat(StatutAide.SOUMISE.peutTransitionnerVers(StatutAide.BROUILLON)).isFalse();
      assertThat(StatutAide.SOUMISE.peutTransitionnerVers(StatutAide.APPROUVEE)).isFalse();
    }

    @Test
    @DisplayName("peutTransitionnerVers - EN_ATTENTE - toutes les transitions")
    void testPeutTransitionnerVersEnAttente() {
      assertThat(StatutAide.EN_ATTENTE.peutTransitionnerVers(StatutAide.EN_COURS_EVALUATION)).isTrue();
      assertThat(StatutAide.EN_ATTENTE.peutTransitionnerVers(StatutAide.ANNULEE)).isTrue();
      assertThat(StatutAide.EN_ATTENTE.peutTransitionnerVers(StatutAide.SOUMISE)).isFalse();
      assertThat(StatutAide.EN_ATTENTE.peutTransitionnerVers(StatutAide.APPROUVEE)).isFalse();
    }

    @Test
    @DisplayName("peutTransitionnerVers - EN_COURS_EVALUATION - toutes les transitions")
    void testPeutTransitionnerVersEnCoursEvaluation() {
      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.EN_ATTENTE)).isFalse();
      assertThat(StatutAide.EN_COURS_EVALUATION.peutTransitionnerVers(StatutAide.TERMINEE)).isFalse();
    }

    @Test
    @DisplayName("peutTransitionnerVers - INFORMATIONS_REQUISES - toutes les transitions")
    void testPeutTransitionnerVersInformationsRequises() {
      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();
      assertThat(StatutAide.INFORMATIONS_REQUISES.peutTransitionnerVers(StatutAide.SOUMISE)).isFalse();
    }

    @Test
    @DisplayName("peutTransitionnerVers - APPROUVEE - toutes les transitions")
    void testPeutTransitionnerVersApprouvee() {
      // APPROUVEE est un statut final (estFinal = true) mais peut transitionner vers EN_COURS_TRAITEMENT ou SUSPENDUE
      // car c'est un statut de décision qui doit permettre le démarrage du traitement
      assertThat(StatutAide.APPROUVEE.peutTransitionnerVers(StatutAide.EN_COURS_TRAITEMENT)).isTrue();
      assertThat(StatutAide.APPROUVEE.peutTransitionnerVers(StatutAide.SUSPENDUE)).isTrue();
      assertThat(StatutAide.APPROUVEE.peutTransitionnerVers(StatutAide.EN_SUIVI)).isFalse();
      assertThat(StatutAide.APPROUVEE.peutTransitionnerVers(StatutAide.EN_COURS_EVALUATION)).isFalse();
      assertThat(StatutAide.APPROUVEE.peutTransitionnerVers(StatutAide.TERMINEE)).isFalse();
    }

    @Test
    @DisplayName("peutTransitionnerVers - APPROUVEE_PARTIELLEMENT - toutes les transitions")
    void testPeutTransitionnerVersApprouveePartiellement() {
      // APPROUVEE_PARTIELLEMENT est un statut final (estFinal = true) mais peut transitionner vers EN_COURS_TRAITEMENT ou SUSPENDUE
      // car c'est un statut de décision qui doit permettre le démarrage du traitement
      assertThat(StatutAide.APPROUVEE_PARTIELLEMENT.peutTransitionnerVers(StatutAide.EN_COURS_TRAITEMENT)).isTrue();
      assertThat(StatutAide.APPROUVEE_PARTIELLEMENT.peutTransitionnerVers(StatutAide.SUSPENDUE)).isTrue();
      assertThat(StatutAide.APPROUVEE_PARTIELLEMENT.peutTransitionnerVers(StatutAide.EN_SUIVI)).isFalse();
      assertThat(StatutAide.APPROUVEE_PARTIELLEMENT.peutTransitionnerVers(StatutAide.APPROUVEE)).isFalse();
    }

    @Test
    @DisplayName("peutTransitionnerVers - EN_COURS_TRAITEMENT - toutes les transitions")
    void testPeutTransitionnerVersEnCoursTraitement() {
      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();
      assertThat(StatutAide.EN_COURS_TRAITEMENT.peutTransitionnerVers(StatutAide.VERSEE)).isFalse();
    }

    @Test
    @DisplayName("peutTransitionnerVers - EN_COURS_VERSEMENT - toutes les transitions")
    void testPeutTransitionnerVersEnCoursVersement() {
      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.EN_COURS_TRAITEMENT)).isFalse();
      assertThat(StatutAide.EN_COURS_VERSEMENT.peutTransitionnerVers(StatutAide.TERMINEE)).isFalse();
    }

    @Test
    @DisplayName("peutTransitionnerVers - SUSPENDUE - toutes les transitions")
    void testPeutTransitionnerVersSuspendue() {
      assertThat(StatutAide.SUSPENDUE.peutTransitionnerVers(StatutAide.EN_COURS_EVALUATION)).isTrue();
      assertThat(StatutAide.SUSPENDUE.peutTransitionnerVers(StatutAide.ANNULEE)).isTrue();
      assertThat(StatutAide.SUSPENDUE.peutTransitionnerVers(StatutAide.APPROUVEE)).isFalse();
      assertThat(StatutAide.SUSPENDUE.peutTransitionnerVers(StatutAide.EN_ATTENTE)).isFalse();
    }

    @Test
    @DisplayName("peutTransitionnerVers - statuts non couverts par switch (default)")
    void testPeutTransitionnerVersDefault() {
      // Les statuts finaux non couverts par le switch retournent false (default -> false)
      assertThat(StatutAide.VERSEE.peutTransitionnerVers(StatutAide.EN_SUIVI)).isFalse();
      assertThat(StatutAide.VERSEE.peutTransitionnerVers(StatutAide.APPROUVEE)).isFalse();
      assertThat(StatutAide.LIVREE.peutTransitionnerVers(StatutAide.EN_SUIVI)).isFalse();
      assertThat(StatutAide.TERMINEE.peutTransitionnerVers(StatutAide.EN_SUIVI)).isFalse();
      assertThat(StatutAide.REJETEE.peutTransitionnerVers(StatutAide.EN_SUIVI)).isFalse();
      assertThat(StatutAide.ANNULEE.peutTransitionnerVers(StatutAide.EN_SUIVI)).isFalse();
      assertThat(StatutAide.EXPIREE.peutTransitionnerVers(StatutAide.EN_SUIVI)).isFalse();
      assertThat(StatutAide.CLOTUREE.peutTransitionnerVers(StatutAide.EN_SUIVI)).isFalse();
      assertThat(StatutAide.EN_SUIVI.peutTransitionnerVers(StatutAide.APPROUVEE)).isFalse();
    }
  }

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

    @ParameterizedTest
    @CsvSource({
        "INFORMATIONS_REQUISES, 1",
        "EN_COURS_EVALUATION, 2",
        "EN_COURS_TRAITEMENT, 2",
        "EN_COURS_VERSEMENT, 2",
        "APPROUVEE, 3",
        "APPROUVEE_PARTIELLEMENT, 3",
        "EN_ATTENTE, 4",
        "SOUMISE, 4",
        "SUSPENDUE, 5",
        "BROUILLON, 6",
        "EN_SUIVI, 7",
        "TERMINEE, 8",
        "VERSEE, 8",
        "LIVREE, 8",
        "REJETEE, 8",
        "ANNULEE, 8",
        "EXPIREE, 8",
        "CLOTUREE, 8"
    })
    @DisplayName("getNiveauPriorite - tous les niveaux")
    void testGetNiveauPriorite(StatutAide statut, int expected) {
      assertThat(statut.getNiveauPriorite()).isEqualTo(expected);
    }
  }

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

    @Test
    @DisplayName("getStatutsFinaux - retourne les statuts finaux")
    void testGetStatutsFinaux() {
      List<StatutAide> statuts = StatutAide.getStatutsFinaux();
      assertThat(statuts).isNotEmpty();
      assertThat(statuts).contains(StatutAide.TERMINEE, StatutAide.VERSEE, StatutAide.LIVREE);
    }

    @Test
    @DisplayName("getStatutsEchec - retourne les statuts d'échec")
    void testGetStatutsEchec() {
      List<StatutAide> statuts = StatutAide.getStatutsEchec();
      assertThat(statuts).isNotEmpty();
      assertThat(statuts).contains(StatutAide.REJETEE, StatutAide.ANNULEE, StatutAide.EXPIREE);
    }

    @Test
    @DisplayName("getStatutsSucces - retourne les statuts de succès")
    void testGetStatutsSucces() {
      List<StatutAide> statuts = StatutAide.getStatutsSucces();
      assertThat(statuts).isNotEmpty();
      assertThat(statuts).contains(StatutAide.VERSEE, StatutAide.LIVREE, StatutAide.TERMINEE);
    }

    @Test
    @DisplayName("getStatutsEnCours - retourne les statuts en cours")
    void testGetStatutsEnCours() {
      List<StatutAide> statuts = StatutAide.getStatutsEnCours();
      assertThat(statuts).isNotEmpty();
      assertThat(statuts).contains(
          StatutAide.EN_COURS_EVALUATION,
          StatutAide.EN_COURS_TRAITEMENT,
          StatutAide.EN_COURS_VERSEMENT);
    }
  }
}
