package dev.lions.unionflow.server.service;

import dev.lions.unionflow.server.api.dto.reference.request.CreateTypeReferenceRequest;
import dev.lions.unionflow.server.api.dto.reference.request.UpdateTypeReferenceRequest;
import dev.lions.unionflow.server.api.dto.reference.response.TypeReferenceResponse;
import dev.lions.unionflow.server.entity.Organisation;
import dev.lions.unionflow.server.service.OrganisationService;
import io.quarkus.test.junit.QuarkusTest;
import io.quarkus.test.TestTransaction;
import jakarta.inject.Inject;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;

import java.util.List;
import java.util.UUID;

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

@QuarkusTest
class TypeReferenceServiceTest {

    @Inject
    TypeReferenceService typeReferenceService;

    @Inject
    OrganisationService organisationService;

    @Test
    @TestTransaction
    @DisplayName("listerDomaines retourne une liste")
    void listerDomaines_returnsList() {
        List<String> list = typeReferenceService.listerDomaines();
        assertThat(list).isNotNull();
    }

    @Test
    @TestTransaction
    @DisplayName("listerParDomaine retourne une liste")
    void listerParDomaine_returnsList() {
        List<TypeReferenceResponse> list = typeReferenceService.listerParDomaine("TEST_DOMAIN", UUID.randomUUID());
        assertThat(list).isNotNull();
    }

    @Test
    @TestTransaction
    @DisplayName("trouverParId avec UUID inexistant lance IllegalArgumentException")
    void trouverParId_inexistant_throws() {
        assertThatThrownBy(() -> typeReferenceService.trouverParId(UUID.randomUUID()))
                .isInstanceOf(IllegalArgumentException.class)
                .hasMessageContaining("introuvable");
    }

    @Test
    @TestTransaction
    @DisplayName("trouverDefaut avec domaine null lance IllegalArgumentException")
    void trouverDefaut_domaineNull_throws() {
        assertThatThrownBy(() -> typeReferenceService.trouverDefaut(null, UUID.randomUUID()))
                .isInstanceOf(IllegalArgumentException.class)
                .hasMessageContaining("domaine");
    }

    @Test
    @TestTransaction
    @DisplayName("trouverDefaut avec domaine blanc lance IllegalArgumentException")
    void trouverDefaut_domaineBlank_throws() {
        assertThatThrownBy(() -> typeReferenceService.trouverDefaut("   ", UUID.randomUUID()))
                .isInstanceOf(IllegalArgumentException.class)
                .hasMessageContaining("domaine");
    }

    @Test
    @TestTransaction
    @DisplayName("creer avec domaine/code/libelle crée la référence")
    void creer_createsReference() {
        String domaine = "SVC_TEST_" + UUID.randomUUID().toString().substring(0, 8);
        String code = "CODE_" + UUID.randomUUID().toString().substring(0, 8);
        CreateTypeReferenceRequest request = CreateTypeReferenceRequest.builder()
                .domaine(domaine)
                .code(code)
                .libelle("Libellé test service")
                .organisationId(null)
                .build();
        TypeReferenceResponse created = typeReferenceService.creer(request);
        assertThat(created).isNotNull();
        assertThat(created.getId()).isNotNull();
        assertThat(created.getDomaine()).isEqualTo(domaine.toUpperCase());
        assertThat(created.getCode()).isEqualTo(code.toUpperCase());
    }

    @Test
    @TestTransaction
    @DisplayName("creer avec estDefaut=true et estSysteme=true conserve les flags")
    void creer_withFlags_setsFlags() {
        String domaine = "SVC_FLAG_" + UUID.randomUUID().toString().substring(0, 8);
        String code = "FLAG_" + UUID.randomUUID().toString().substring(0, 8);
        CreateTypeReferenceRequest request = CreateTypeReferenceRequest.builder()
                .domaine(domaine)
                .code(code)
                .libelle("Libellé flag")
                .estDefaut(true)
                .estSysteme(true)
                .ordreAffichage(5)
                .organisationId(null)
                .build();
        TypeReferenceResponse created = typeReferenceService.creer(request);
        assertThat(created.getEstDefaut()).isTrue();
        assertThat(created.getEstSysteme()).isTrue();
        assertThat(created.getOrdreAffichage()).isEqualTo(5);
    }

    @Test
    @TestTransaction
    @DisplayName("creer avec code déjà existant dans le même domaine lance IllegalArgumentException")
    void creer_duplicateCode_throws() {
        String domaine = "SVC_DUP_" + UUID.randomUUID().toString().substring(0, 8);
        String code = "DUP_CODE";
        CreateTypeReferenceRequest request = CreateTypeReferenceRequest.builder()
                .domaine(domaine)
                .code(code)
                .libelle("Premier")
                .organisationId(null)
                .build();
        typeReferenceService.creer(request);

        CreateTypeReferenceRequest dup = CreateTypeReferenceRequest.builder()
                .domaine(domaine)
                .code(code)
                .libelle("Second")
                .organisationId(null)
                .build();
        assertThatThrownBy(() -> typeReferenceService.creer(dup))
                .isInstanceOf(IllegalArgumentException.class)
                .hasMessageContaining("existe déjà");
    }

    @Test
    @TestTransaction
    @DisplayName("trouverParId retourne la référence créée")
    void trouverParId_existant_returnsReference() {
        String domaine = "SVC_FIND_" + UUID.randomUUID().toString().substring(0, 8);
        String code = "FIND_" + UUID.randomUUID().toString().substring(0, 8);
        TypeReferenceResponse created = typeReferenceService.creer(
                CreateTypeReferenceRequest.builder()
                        .domaine(domaine)
                        .code(code)
                        .libelle("Trouvable")
                        .organisationId(null)
                        .build());

        TypeReferenceResponse found = typeReferenceService.trouverParId(created.getId());
        assertThat(found).isNotNull();
        assertThat(found.getId()).isEqualTo(created.getId());
        assertThat(found.getCode()).isEqualTo(code.toUpperCase());
    }

    @Test
    @TestTransaction
    @DisplayName("trouverDefaut sans valeur par défaut pour le domaine lance IllegalArgumentException")
    void trouverDefaut_noDefault_throws() {
        String domaine = "SVC_NODEF_" + UUID.randomUUID().toString().substring(0, 8);
        assertThatThrownBy(() -> typeReferenceService.trouverDefaut(domaine, null))
                .isInstanceOf(IllegalArgumentException.class)
                .hasMessageContaining("Aucune valeur par défaut");
    }

    @Test
    @TestTransaction
    @DisplayName("trouverDefaut retourne la référence marquée comme défaut")
    void trouverDefaut_withDefault_returnsIt() {
        String domaine = "SVC_DEF_" + UUID.randomUUID().toString().substring(0, 8);
        String code = "DEF_" + UUID.randomUUID().toString().substring(0, 8);
        typeReferenceService.creer(
                CreateTypeReferenceRequest.builder()
                        .domaine(domaine)
                        .code(code)
                        .libelle("Défaut")
                        .estDefaut(true)
                        .organisationId(null)
                        .build());

        TypeReferenceResponse defaut = typeReferenceService.trouverDefaut(domaine, null);
        assertThat(defaut).isNotNull();
        assertThat(defaut.getEstDefaut()).isTrue();
    }

    @Test
    @TestTransaction
    @DisplayName("modifier: met à jour le libellé")
    void modifier_updatesLibelle() {
        String domaine = "SVC_MOD_" + UUID.randomUUID().toString().substring(0, 8);
        String code = "MOD_" + UUID.randomUUID().toString().substring(0, 8);
        TypeReferenceResponse created = typeReferenceService.creer(
                CreateTypeReferenceRequest.builder()
                        .domaine(domaine)
                        .code(code)
                        .libelle("Ancien libellé")
                        .organisationId(null)
                        .build());

        UpdateTypeReferenceRequest updateRequest = new UpdateTypeReferenceRequest(
                null,           // code (pas de changement)
                "Nouveau libellé",
                null, null, null, null, null, null, null, null, null);

        TypeReferenceResponse updated = typeReferenceService.modifier(created.getId(), updateRequest);
        assertThat(updated.getLibelle()).isEqualTo("Nouveau libellé");
    }

    @Test
    @TestTransaction
    @DisplayName("modifier avec UUID inexistant lance IllegalArgumentException")
    void modifier_inexistant_throws() {
        UpdateTypeReferenceRequest updateRequest = new UpdateTypeReferenceRequest(
                null, "Libellé", null, null, null, null, null, null, null, null, null);

        assertThatThrownBy(() -> typeReferenceService.modifier(UUID.randomUUID(), updateRequest))
                .isInstanceOf(IllegalArgumentException.class)
                .hasMessageContaining("introuvable");
    }

    @Test
    @TestTransaction
    @DisplayName("supprimer: supprime une référence non-système")
    void supprimer_nonSysteme_succeeds() {
        String domaine = "SVC_DEL_" + UUID.randomUUID().toString().substring(0, 8);
        String code = "DEL_" + UUID.randomUUID().toString().substring(0, 8);
        TypeReferenceResponse created = typeReferenceService.creer(
                CreateTypeReferenceRequest.builder()
                        .domaine(domaine)
                        .code(code)
                        .libelle("À supprimer")
                        .estSysteme(false)
                        .organisationId(null)
                        .build());

        typeReferenceService.supprimer(created.getId());

        assertThatThrownBy(() -> typeReferenceService.trouverParId(created.getId()))
                .isInstanceOf(IllegalArgumentException.class);
    }

    @Test
    @TestTransaction
    @DisplayName("supprimer une référence système lance IllegalArgumentException")
    void supprimer_systeme_throws() {
        String domaine = "SVC_SYS_" + UUID.randomUUID().toString().substring(0, 8);
        String code = "SYS_" + UUID.randomUUID().toString().substring(0, 8);
        TypeReferenceResponse created = typeReferenceService.creer(
                CreateTypeReferenceRequest.builder()
                        .domaine(domaine)
                        .code(code)
                        .libelle("Système")
                        .estSysteme(true)
                        .organisationId(null)
                        .build());

        assertThatThrownBy(() -> typeReferenceService.supprimer(created.getId()))
                .isInstanceOf(IllegalArgumentException.class)
                .hasMessageContaining("système");
    }

    @Test
    @TestTransaction
    @DisplayName("supprimer UUID inexistant lance IllegalArgumentException")
    void supprimer_inexistant_throws() {
        assertThatThrownBy(() -> typeReferenceService.supprimer(UUID.randomUUID()))
                .isInstanceOf(IllegalArgumentException.class)
                .hasMessageContaining("introuvable");
    }

    @Test
    @TestTransaction
    @DisplayName("supprimerPourSuperAdmin: supprime même une référence système")
    void supprimerPourSuperAdmin_systeme_succeeds() {
        String domaine = "SVC_SADM_" + UUID.randomUUID().toString().substring(0, 8);
        String code = "SADM_" + UUID.randomUUID().toString().substring(0, 8);
        TypeReferenceResponse created = typeReferenceService.creer(
                CreateTypeReferenceRequest.builder()
                        .domaine(domaine)
                        .code(code)
                        .libelle("Système super admin")
                        .estSysteme(true)
                        .organisationId(null)
                        .build());

        typeReferenceService.supprimerPourSuperAdmin(created.getId());

        assertThatThrownBy(() -> typeReferenceService.trouverParId(created.getId()))
                .isInstanceOf(IllegalArgumentException.class);
    }

    @Test
    @TestTransaction
    @DisplayName("supprimerPourSuperAdmin UUID inexistant lance IllegalArgumentException")
    void supprimerPourSuperAdmin_inexistant_throws() {
        assertThatThrownBy(() -> typeReferenceService.supprimerPourSuperAdmin(UUID.randomUUID()))
                .isInstanceOf(IllegalArgumentException.class)
                .hasMessageContaining("introuvable");
    }

    @Test
    @TestTransaction
    @DisplayName("modifier: changement de code sur référence non-système réussit")
    void modifier_codeChange_nonSysteme_succeeds() {
        String domaine = "SVC_CODECHANGE_" + UUID.randomUUID().toString().substring(0, 8);
        String oldCode = "OLD_" + UUID.randomUUID().toString().substring(0, 8);
        String newCode = "NEW_" + UUID.randomUUID().toString().substring(0, 8);

        TypeReferenceResponse created = typeReferenceService.creer(
                CreateTypeReferenceRequest.builder()
                        .domaine(domaine)
                        .code(oldCode)
                        .libelle("Changement code")
                        .estSysteme(false)
                        .organisationId(null)
                        .build());

        UpdateTypeReferenceRequest updateRequest = new UpdateTypeReferenceRequest(
                newCode, null, null, null, null, null, null, null, null, null, null);

        TypeReferenceResponse updated = typeReferenceService.modifier(created.getId(), updateRequest);
        assertThat(updated.getCode()).isEqualTo(newCode.toUpperCase());
    }

    @Test
    @TestTransaction
    @DisplayName("modifier: changement de code sur référence système lance IllegalArgumentException")
    void modifier_codeChange_systeme_throws() {
        String domaine = "SVC_SYSCODE_" + UUID.randomUUID().toString().substring(0, 8);
        String code = "ORIG_" + UUID.randomUUID().toString().substring(0, 8);

        TypeReferenceResponse created = typeReferenceService.creer(
                CreateTypeReferenceRequest.builder()
                        .domaine(domaine)
                        .code(code)
                        .libelle("Système immutable")
                        .estSysteme(true)
                        .organisationId(null)
                        .build());

        UpdateTypeReferenceRequest updateRequest = new UpdateTypeReferenceRequest(
                "CHANGED_CODE", null, null, null, null, null, null, null, null, null, null);

        assertThatThrownBy(() -> typeReferenceService.modifier(created.getId(), updateRequest))
                .isInstanceOf(IllegalArgumentException.class)
                .hasMessageContaining("système");
    }

    @Test
    @TestTransaction
    @DisplayName("modifier: code fourni mais identique à l'existant → condition L186 equalsIgnoreCase=true → skip (branche false)")
    void modifier_sameCode_noCodeChange_skipsCheck() {
        String domaine = "SVC_SAMECODE_" + UUID.randomUUID().toString().substring(0, 8);
        String code = "SAME_CODE_" + UUID.randomUUID().toString().substring(0, 6);

        TypeReferenceResponse created = typeReferenceService.creer(
                CreateTypeReferenceRequest.builder()
                        .domaine(domaine)
                        .code(code)
                        .libelle("Original libelle")
                        .estSysteme(false)
                        .organisationId(null)
                        .build());

        // Même code (case-insensitive) → !equalsIgnoreCase = false → if body skipped
        UpdateTypeReferenceRequest updateRequest = new UpdateTypeReferenceRequest(
                code.toLowerCase(), "Nouveau libelle", null, null, null, null, null, null, null, null, null);

        TypeReferenceResponse updated = typeReferenceService.modifier(created.getId(), updateRequest);
        assertThat(updated).isNotNull();
        assertThat(updated.getLibelle()).isEqualTo("Nouveau libelle");
    }

    @Test
    @TestTransaction
    @DisplayName("listerParDomaine avec organisationId null retourne les références globales")
    void listerParDomaine_globalScope_returnsList() {
        String domaine = "SVC_GLOBAL_" + UUID.randomUUID().toString().substring(0, 8);
        typeReferenceService.creer(
                CreateTypeReferenceRequest.builder()
                        .domaine(domaine)
                        .code("G1_" + UUID.randomUUID().toString().substring(0, 6))
                        .libelle("Global 1")
                        .organisationId(null)
                        .build());

        List<TypeReferenceResponse> list = typeReferenceService.listerParDomaine(domaine, null);
        assertThat(list).isNotEmpty();
    }

    // ================================================================
    // creer — branche organisationId non-null (ligne 148-152)
    // toResponse — branche organisation non-null (ligne 285-288)
    // ================================================================

    @Test
    @TestTransaction
    @DisplayName("creer avec organisationId non-null lie l'organisation et retourne organisationId dans la réponse")
    void creer_avecOrganisationId_lieOrganisation() {
        // Créer une organisation réelle
        Organisation org = new Organisation();
        org.setNom("OrgTypeRef-" + UUID.randomUUID().toString().substring(0, 8));
        org.setEmail("org-typeref-" + UUID.randomUUID().toString().substring(0, 6) + "@test.com");
        org.setTypeOrganisation("ASSOCIATION");
        org.setStatut("ACTIVE");
        org.setActif(true);
        organisationService.creerOrganisation(org, "admin@test.com");

        String domaine = "SVC_ORG_" + UUID.randomUUID().toString().substring(0, 8);
        String code = "ORG_" + UUID.randomUUID().toString().substring(0, 8);

        CreateTypeReferenceRequest request = CreateTypeReferenceRequest.builder()
                .domaine(domaine)
                .code(code)
                .libelle("Référence avec organisation")
                .organisationId(org.getId())  // non-null → branche L148
                .build();

        TypeReferenceResponse created = typeReferenceService.creer(request);

        assertThat(created).isNotNull();
        assertThat(created.getId()).isNotNull();
        // toResponse branche organisation non-null (L285-288) → organisationId peuplé
        assertThat(created.getOrganisationId()).isEqualTo(org.getId());
    }

    // ================================================================
    // modifier — branche code change quand organisation non-null (ligne 195-197)
    // ================================================================

    @Test
    @TestTransaction
    @DisplayName("modifier: changement de code sur référence avec organisation non-null appelle validerUnicite avec orgId")
    void modifier_codeChange_avecOrganisation_valideUniciteAvecOrgId() {
        // Créer une organisation réelle
        Organisation org = new Organisation();
        org.setNom("OrgMod-" + UUID.randomUUID().toString().substring(0, 8));
        org.setEmail("org-mod-" + UUID.randomUUID().toString().substring(0, 6) + "@test.com");
        org.setTypeOrganisation("ASSOCIATION");
        org.setStatut("ACTIVE");
        org.setActif(true);
        organisationService.creerOrganisation(org, "admin@test.com");

        String domaine = "SVC_ORGMOD_" + UUID.randomUUID().toString().substring(0, 6);
        String oldCode = "OLD_ORG_" + UUID.randomUUID().toString().substring(0, 6);
        String newCode = "NEW_ORG_" + UUID.randomUUID().toString().substring(0, 6);

        TypeReferenceResponse created = typeReferenceService.creer(
                CreateTypeReferenceRequest.builder()
                        .domaine(domaine)
                        .code(oldCode)
                        .libelle("Avec org")
                        .estSysteme(false)
                        .organisationId(org.getId())
                        .build());

        // Modifier le code avec l'organisation non-null → L195-197 : orgId = entity.getOrganisation().getId()
        UpdateTypeReferenceRequest updateRequest = new UpdateTypeReferenceRequest(
                newCode, null, null, null, null, null, null, null, null, null, null);

        TypeReferenceResponse updated = typeReferenceService.modifier(created.getId(), updateRequest);

        assertThat(updated.getCode()).isEqualTo(newCode.toUpperCase());
        assertThat(updated.getOrganisationId()).isEqualTo(org.getId());
    }

    @Test
    @TestTransaction
    @DisplayName("modifier avec tous les champs non-null couvre toutes les branches de appliquerMiseAJour")
    void modifier_allFieldsNonNull_coversAllAppliquerMiseAjourBranches() {
        String domaine = "SVC_ALL_" + UUID.randomUUID().toString().substring(0, 8);
        String code = "ALL_" + UUID.randomUUID().toString().substring(0, 8);
        TypeReferenceResponse created = typeReferenceService.creer(
                CreateTypeReferenceRequest.builder()
                        .domaine(domaine)
                        .code(code)
                        .libelle("Libellé initial")
                        .estSysteme(false)
                        .organisationId(null)
                        .build());

        // Tous les champs non-null → couvre toutes les branches if dans appliquerMiseAJour
        // (description, icone, couleur, severity, ordreAffichage, estDefaut, actif)
        UpdateTypeReferenceRequest updateRequest = new UpdateTypeReferenceRequest(
                null,               // code  (pas de changement de code)
                "Nouveau libellé",  // libelle
                "Nouvelle desc",    // description
                "icon-test",        // icone
                "#FF0000",          // couleur
                "warning",          // severity
                10,                 // ordreAffichage
                true,               // estDefaut
                false,              // actif
                null,               // categorie
                null                // modulesRequis
        );

        TypeReferenceResponse updated = typeReferenceService.modifier(created.getId(), updateRequest);

        assertThat(updated.getLibelle()).isEqualTo("Nouveau libellé");
        assertThat(updated.getDescription()).isEqualTo("Nouvelle desc");
        assertThat(updated.getIcone()).isEqualTo("icon-test");
        assertThat(updated.getCouleur()).isEqualTo("#FF0000");
        assertThat(updated.getSeverity()).isEqualTo("warning");
        assertThat(updated.getOrdreAffichage()).isEqualTo(10);
        assertThat(updated.getEstDefaut()).isTrue();
    }

    // ================================================================
    // validerLbcFtSiFinancierSolidaire — règle BCEAO
    // ================================================================

    @Test
    @TestTransaction
    @DisplayName("creer FINANCIER_SOLIDAIRE sans LCB_FT lance IllegalArgumentException")
    void creer_financierSolidaire_sansLbcFt_throws() {
        String domaine = "TYPE_ORGANISATION";
        CreateTypeReferenceRequest request = CreateTypeReferenceRequest.builder()
                .domaine(domaine)
                .code("FS_" + UUID.randomUUID().toString().substring(0, 8))
                .libelle("Mutuelle test")
                .categorie("FINANCIER_SOLIDAIRE")
                .modulesRequis("COTISATIONS,EPARGNE,CREDIT")
                .organisationId(null)
                .build();

        assertThatThrownBy(() -> typeReferenceService.creer(request))
                .isInstanceOf(IllegalArgumentException.class)
                .hasMessageContaining("LCB_FT");
    }

    @Test
    @TestTransaction
    @DisplayName("creer FINANCIER_SOLIDAIRE avec modulesRequis null lance IllegalArgumentException")
    void creer_financierSolidaire_modulesNull_throws() {
        CreateTypeReferenceRequest request = CreateTypeReferenceRequest.builder()
                .domaine("TYPE_ORGANISATION")
                .code("FS_NULL_" + UUID.randomUUID().toString().substring(0, 6))
                .libelle("Mutuelle sans modules")
                .categorie("FINANCIER_SOLIDAIRE")
                .modulesRequis(null)
                .organisationId(null)
                .build();

        assertThatThrownBy(() -> typeReferenceService.creer(request))
                .isInstanceOf(IllegalArgumentException.class)
                .hasMessageContaining("LCB_FT");
    }

    @Test
    @TestTransaction
    @DisplayName("creer FINANCIER_SOLIDAIRE avec LCB_FT réussit")
    void creer_financierSolidaire_avecLbcFt_succes() {
        CreateTypeReferenceRequest request = CreateTypeReferenceRequest.builder()
                .domaine("TYPE_ORGANISATION")
                .code("FS_OK_" + UUID.randomUUID().toString().substring(0, 6))
                .libelle("Mutuelle conforme")
                .categorie("FINANCIER_SOLIDAIRE")
                .modulesRequis("COTISATIONS,EPARGNE,CREDIT,LCB_FT")
                .organisationId(null)
                .build();

        TypeReferenceResponse created = typeReferenceService.creer(request);
        assertThat(created).isNotNull();
        assertThat(created.getModulesRequis()).contains("LCB_FT");
    }

    @Test
    @TestTransaction
    @DisplayName("creer catégorie ASSOCIATIF sans LCB_FT réussit (pas de contrainte)")
    void creer_autreCategorie_sansLbcFt_succes() {
        CreateTypeReferenceRequest request = CreateTypeReferenceRequest.builder()
                .domaine("TYPE_ORGANISATION")
                .code("ASSOC_" + UUID.randomUUID().toString().substring(0, 6))
                .libelle("Association simple")
                .categorie("ASSOCIATIF")
                .modulesRequis("COTISATIONS,EVENEMENTS")
                .organisationId(null)
                .build();

        TypeReferenceResponse created = typeReferenceService.creer(request);
        assertThat(created).isNotNull();
    }

    @Test
    @TestTransaction
    @DisplayName("modifier FINANCIER_SOLIDAIRE en retirant LCB_FT lance IllegalArgumentException")
    void modifier_financierSolidaire_suppressionLbcFt_throws() {
        TypeReferenceResponse created = typeReferenceService.creer(
                CreateTypeReferenceRequest.builder()
                        .domaine("TYPE_ORGANISATION")
                        .code("FS_MOD_" + UUID.randomUUID().toString().substring(0, 6))
                        .libelle("Mutuelle à modifier")
                        .categorie("FINANCIER_SOLIDAIRE")
                        .modulesRequis("COTISATIONS,LCB_FT")
                        .organisationId(null)
                        .build());

        UpdateTypeReferenceRequest update = new UpdateTypeReferenceRequest(
                null, null, null, null, null, null, null, null, null,
                null, // categorie inchangée → reste FINANCIER_SOLIDAIRE
                "COTISATIONS,EPARGNE"); // LCB_FT retiré

        assertThatThrownBy(() -> typeReferenceService.modifier(created.getId(), update))
                .isInstanceOf(IllegalArgumentException.class)
                .hasMessageContaining("LCB_FT");
    }

    @Test
    @TestTransaction
    @DisplayName("modifier FINANCIER_SOLIDAIRE sans changer modulesRequis réussit")
    void modifier_financierSolidaire_sansChangerModules_succes() {
        TypeReferenceResponse created = typeReferenceService.creer(
                CreateTypeReferenceRequest.builder()
                        .domaine("TYPE_ORGANISATION")
                        .code("FS_NOCHG_" + UUID.randomUUID().toString().substring(0, 5))
                        .libelle("Mutuelle initiale")
                        .categorie("FINANCIER_SOLIDAIRE")
                        .modulesRequis("COTISATIONS,LCB_FT")
                        .organisationId(null)
                        .build());

        UpdateTypeReferenceRequest update = new UpdateTypeReferenceRequest(
                null, "Mutuelle renommée", null, null, null, null, null, null, null,
                null, // categorie inchangée
                null); // modulesRequis inchangé → LCB_FT conservé en entité

        TypeReferenceResponse updated = typeReferenceService.modifier(created.getId(), update);
        assertThat(updated.getLibelle()).isEqualTo("Mutuelle renommée");
        assertThat(updated.getModulesRequis()).contains("LCB_FT");
    }
}
