package dev.lions.unionflow.server.security;

import dev.lions.unionflow.server.service.KeycloakService;
import jakarta.enterprise.context.ApplicationScoped;
import jakarta.inject.Inject;
import java.util.Set;
import org.jboss.logging.Logger;

/**
 * Configuration et utilitaires de sécurité avec Keycloak
 *
 * @author UnionFlow Team
 * @version 1.0
 * @since 2025-01-15
 */
@ApplicationScoped
public class SecurityConfig {

  private static final Logger LOG = Logger.getLogger(SecurityConfig.class);

  @Inject KeycloakService keycloakService;

  /** Rôles disponibles dans l'application */
  public static class Roles {
    public static final String ADMIN = "ADMIN";
    public static final String GESTIONNAIRE_MEMBRE = "GESTIONNAIRE_MEMBRE";
    public static final String TRESORIER = "TRESORIER";
    public static final String SECRETAIRE = "SECRETAIRE";
    public static final String MEMBRE = "MEMBRE";
    public static final String PRESIDENT = "PRESIDENT";
    public static final String VICE_PRESIDENT = "VICE_PRESIDENT";
    public static final String ORGANISATEUR_EVENEMENT = "ORGANISATEUR_EVENEMENT";
    public static final String GESTIONNAIRE_SOLIDARITE = "GESTIONNAIRE_SOLIDARITE";
    public static final String AUDITEUR = "AUDITEUR";
  }

  /** Permissions disponibles dans l'application */
  public static class Permissions {
    // Permissions membres
    public static final String CREATE_MEMBRE = "CREATE_MEMBRE";
    public static final String READ_MEMBRE = "READ_MEMBRE";
    public static final String UPDATE_MEMBRE = "UPDATE_MEMBRE";
    public static final String DELETE_MEMBRE = "DELETE_MEMBRE";

    // Permissions organisations
    public static final String CREATE_ORGANISATION = "CREATE_ORGANISATION";
    public static final String READ_ORGANISATION = "READ_ORGANISATION";
    public static final String UPDATE_ORGANISATION = "UPDATE_ORGANISATION";
    public static final String DELETE_ORGANISATION = "DELETE_ORGANISATION";

    // Permissions événements
    public static final String CREATE_EVENEMENT = "CREATE_EVENEMENT";
    public static final String READ_EVENEMENT = "READ_EVENEMENT";
    public static final String UPDATE_EVENEMENT = "UPDATE_EVENEMENT";
    public static final String DELETE_EVENEMENT = "DELETE_EVENEMENT";

    // Permissions finances
    public static final String CREATE_COTISATION = "CREATE_COTISATION";
    public static final String READ_COTISATION = "READ_COTISATION";
    public static final String UPDATE_COTISATION = "UPDATE_COTISATION";
    public static final String DELETE_COTISATION = "DELETE_COTISATION";

    // Permissions solidarité
    public static final String CREATE_SOLIDARITE = "CREATE_SOLIDARITE";
    public static final String READ_SOLIDARITE = "READ_SOLIDARITE";
    public static final String UPDATE_SOLIDARITE = "UPDATE_SOLIDARITE";
    public static final String DELETE_SOLIDARITE = "DELETE_SOLIDARITE";

    // Permissions administration
    public static final String ADMIN_USERS = "ADMIN_USERS";
    public static final String ADMIN_SYSTEM = "ADMIN_SYSTEM";
    public static final String VIEW_REPORTS = "VIEW_REPORTS";
    public static final String EXPORT_DATA = "EXPORT_DATA";
  }

  /**
   * Vérifie si l'utilisateur actuel a un rôle spécifique
   *
   * @param role le rôle à vérifier
   * @return true si l'utilisateur a le rôle
   */
  public boolean hasRole(String role) {
    return keycloakService.hasRole(role);
  }

  /**
   * Vérifie si l'utilisateur actuel a au moins un des rôles spécifiés
   *
   * @param roles les rôles à vérifier
   * @return true si l'utilisateur a au moins un des rôles
   */
  public boolean hasAnyRole(String... roles) {
    return keycloakService.hasAnyRole(roles);
  }

  /**
   * Vérifie si l'utilisateur actuel a tous les rôles spécifiés
   *
   * @param roles les rôles à vérifier
   * @return true si l'utilisateur a tous les rôles
   */
  public boolean hasAllRoles(String... roles) {
    return keycloakService.hasAllRoles(roles);
  }

  /**
   * Obtient l'ID de l'utilisateur actuel
   *
   * @return l'ID de l'utilisateur ou null si non authentifié
   */
  public String getCurrentUserId() {
    return keycloakService.getCurrentUserId();
  }

  /**
   * Obtient l'email de l'utilisateur actuel
   *
   * @return l'email de l'utilisateur ou null si non authentifié
   */
  public String getCurrentUserEmail() {
    return keycloakService.getCurrentUserEmail();
  }

  /**
   * Obtient tous les rôles de l'utilisateur actuel
   *
   * @return les rôles de l'utilisateur
   */
  public Set<String> getCurrentUserRoles() {
    return keycloakService.getCurrentUserRoles();
  }

  /**
   * Vérifie si l'utilisateur actuel est authentifié
   *
   * @return true si l'utilisateur est authentifié
   */
  public boolean isAuthenticated() {
    return keycloakService.isAuthenticated();
  }

  /**
   * Vérifie si l'utilisateur actuel est un administrateur
   *
   * @return true si l'utilisateur est administrateur
   */
  public boolean isAdmin() {
    return hasRole(Roles.ADMIN);
  }

  /**
   * Vérifie si l'utilisateur actuel peut gérer les membres
   *
   * @return true si l'utilisateur peut gérer les membres
   */
  public boolean canManageMembers() {
    return hasAnyRole(Roles.ADMIN, Roles.GESTIONNAIRE_MEMBRE, Roles.PRESIDENT, Roles.SECRETAIRE);
  }

  /**
   * Vérifie si l'utilisateur actuel peut gérer les finances
   *
   * @return true si l'utilisateur peut gérer les finances
   */
  public boolean canManageFinances() {
    return hasAnyRole(Roles.ADMIN, Roles.TRESORIER, Roles.PRESIDENT);
  }

  /**
   * Vérifie si l'utilisateur actuel peut gérer les événements
   *
   * @return true si l'utilisateur peut gérer les événements
   */
  public boolean canManageEvents() {
    return hasAnyRole(Roles.ADMIN, Roles.ORGANISATEUR_EVENEMENT, Roles.PRESIDENT, Roles.SECRETAIRE);
  }

  /**
   * Vérifie si l'utilisateur actuel peut gérer les organisations
   *
   * @return true si l'utilisateur peut gérer les organisations
   */
  public boolean canManageOrganizations() {
    return hasAnyRole(Roles.ADMIN, Roles.PRESIDENT);
  }

  /**
   * Vérifie si l'utilisateur actuel peut accéder aux données d'un membre spécifique
   *
   * @param membreId l'ID du membre
   * @return true si l'utilisateur peut accéder aux données
   */
  public boolean canAccessMemberData(String membreId) {
    // Un utilisateur peut toujours accéder à ses propres données
    if (membreId.equals(getCurrentUserId())) {
      return true;
    }

    // Les gestionnaires peuvent accéder aux données de tous les membres
    return canManageMembers();
  }

  /** Log les informations de sécurité pour debug */
  public void logSecurityInfo() {
    if (LOG.isDebugEnabled()) {
      if (isAuthenticated()) {
        LOG.debugf(
            "Utilisateur authentifié: %s, Rôles: %s", getCurrentUserEmail(), getCurrentUserRoles());
      } else {
        LOG.debug("Utilisateur non authentifié");
      }
    }
  }
}
