package dev.lions.unionflow.server.service;
import dev.lions.unionflow.server.entity.Organisation;
import dev.lions.unionflow.server.repository.OrganisationRepository;
import jakarta.enterprise.context.ApplicationScoped;
import jakarta.inject.Inject;
import java.util.Arrays;
import java.util.Collections;
import java.util.EnumSet;
import java.util.LinkedHashSet;
import java.util.Optional;
import java.util.Set;
import java.util.UUID;
import org.jboss.logging.Logger;
/**
* Service de gestion des modules actifs par organisation.
*
*
Architecture Option C — les modules actifs sont déterminés par le TYPE
* d'organisation, pas par le plan tarifaire. Le plan impacte uniquement la
* profondeur fonctionnelle (reporting, API, fédération).
*
*
Les modules sont regroupés en deux catégories :
*
* - MODULES_COMMUNS — accessibles à tous les types d'org
* - Modules métier — spécifiques au type d'org (TONTINE, CREDIT, etc.)
*
*/
@ApplicationScoped
public class OrganisationModuleService {
private static final Logger LOG = Logger.getLogger(OrganisationModuleService.class);
/** Modules présents sur toutes les organisations quelle que soit leur nature. */
public static final Set MODULES_COMMUNS = Set.of(
"MEMBRES",
"COTISATIONS",
"EVENEMENTS",
"COMMUNICATION",
"DOCUMENTS",
"NOTIFICATION",
"AIDE"
);
@Inject
OrganisationRepository organisationRepository;
/**
* Retourne l'ensemble des modules actifs pour une organisation donnée.
* Combine les modules communs avec les modules métier du type d'org.
*/
public Set getModulesActifs(UUID organisationId) {
Optional opt = organisationRepository.findByIdOptional(organisationId);
if (opt.isEmpty()) {
LOG.warnf("Organisation introuvable : %s", organisationId);
return MODULES_COMMUNS;
}
return getModulesActifs(opt.get());
}
/**
* Retourne l'ensemble des modules actifs pour une organisation.
*/
public Set getModulesActifs(Organisation organisation) {
Set modules = new LinkedHashSet<>(MODULES_COMMUNS);
// 1. Modules issus du champ modulesActifs persisté (calculé depuis types_reference en V18)
String modulesActifsCsv = organisation.getModulesActifs();
if (modulesActifsCsv != null && !modulesActifsCsv.isBlank()) {
Arrays.stream(modulesActifsCsv.split(","))
.map(String::trim)
.filter(s -> !s.isEmpty())
.forEach(modules::add);
return modules;
}
// 2. Fallback : déduction depuis le typeOrganisation si modulesActifs non renseigné
modules.addAll(getModulesParType(organisation.getTypeOrganisation()));
return modules;
}
/**
* Vérifie si un module spécifique est actif pour une organisation.
*/
public boolean isModuleActif(UUID organisationId, String module) {
return getModulesActifs(organisationId).contains(module.toUpperCase());
}
/**
* Retourne les modules métier associés à un type d'organisation.
* Utilisé en fallback si la colonne modules_actifs n'est pas peuplée.
*/
public Set getModulesParType(String typeOrganisation) {
if (typeOrganisation == null) {
return Collections.emptySet();
}
Set modules = new LinkedHashSet<>();
switch (typeOrganisation.toUpperCase()) {
case "TONTINE" -> {
modules.add("TONTINE");
modules.add("FINANCE");
}
case "MUTUELLE", "MUTUELLE_EPARGNE", "MUTUELLE_CREDIT" -> {
modules.add("EPARGNE");
modules.add("CREDIT");
modules.add("FINANCE");
modules.add("LCB_FT");
}
case "COOPERATIVE" -> {
modules.add("AGRICULTURE");
modules.add("FINANCE");
}
case "ONG", "FONDATION" -> {
modules.add("PROJETS_ONG");
modules.add("COLLECTE_FONDS");
modules.add("FINANCE");
}
case "EGLISE", "GROUPE_PRIERE" -> {
modules.add("CULTE_DONS");
}
case "SYNDICAT", "ORDRE_PROFESSIONNEL", "FEDERATION" -> {
modules.add("VOTES");
modules.add("REGISTRE_AGREMENT");
}
case "GIE" -> {
modules.add("FINANCE");
}
case "ASSOCIATION", "CLUB_SERVICE" -> {
modules.add("TONTINE");
modules.add("VOTES");
}
case "CLUB_SPORTIF", "CLUB_CULTUREL" -> {
modules.add("VOTES");
}
default -> LOG.debugf("Type d''organisation non reconnu pour module mapping : %s", typeOrganisation);
}
return modules;
}
/**
* Retourne la liste des modules actifs sous forme de tableau JSON-friendly.
* Utilisé par l'endpoint /api/organisations/{id}/modules-actifs
*/
public ModulesActifsResponse getModulesActifsResponse(UUID organisationId) {
Optional opt = organisationRepository.findByIdOptional(organisationId);
if (opt.isEmpty()) {
return new ModulesActifsResponse(organisationId, Collections.emptySet(), "UNKNOWN");
}
Organisation org = opt.get();
Set modules = getModulesActifs(org);
return new ModulesActifsResponse(organisationId, modules, org.getTypeOrganisation());
}
/** DTO de réponse pour l'endpoint modules-actifs. */
public record ModulesActifsResponse(UUID organisationId, Set modules, String typeOrganisation) {}
}